[MERGE] chm - improved subtype - fixes
bzr revid: fp@openerp.com-20121002204023-8v3jf2n84xe2jol9
This commit is contained in:
commit
c93d70e919
|
@ -1308,17 +1308,19 @@ class account_invoice(osv.osv):
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)),
|
||||||
|
subtype="account.mt_invoice_new", context=context)
|
||||||
|
|
||||||
def confirm_paid_send_note(self, cr, uid, ids, context=None):
|
def confirm_paid_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)),
|
||||||
|
subtype="account.mt_invoice_paid", context=context)
|
||||||
|
|
||||||
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
|
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)),
|
||||||
|
context=context)
|
||||||
|
|
||||||
account_invoice()
|
|
||||||
|
|
||||||
class account_invoice_line(osv.osv):
|
class account_invoice_line(osv.osv):
|
||||||
|
|
||||||
|
|
|
@ -278,7 +278,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -438,7 +437,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -518,7 +518,6 @@
|
||||||
<!--
|
<!--
|
||||||
Account Statement Sequences
|
Account Statement Sequences
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<record id="sequence_reconcile" model="ir.sequence.type">
|
<record id="sequence_reconcile" model="ir.sequence.type">
|
||||||
<field name="name">Account Reconcile</field>
|
<field name="name">Account Reconcile</field>
|
||||||
<field name="code">account.reconcile</field>
|
<field name="code">account.reconcile</field>
|
||||||
|
@ -554,8 +553,6 @@
|
||||||
<field eval="1" name="number_next"/>
|
<field eval="1" name="number_next"/>
|
||||||
<field eval="1" name="number_increment"/>
|
<field eval="1" name="number_increment"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Invoice requests (deprecated)
|
Invoice requests (deprecated)
|
||||||
-->
|
-->
|
||||||
|
@ -564,7 +561,14 @@
|
||||||
<field name="object">account.invoice</field>
|
<field name="object">account.invoice</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- mail: subtypes -->
|
||||||
|
<record id="mt_invoice_new" model="mail.message.subtype">
|
||||||
|
<field name="name">created</field>
|
||||||
|
<field name="res_model">account.invoice</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_invoice_paid" model="mail.message.subtype">
|
||||||
|
<field name="name">paid</field>
|
||||||
|
<field name="res_model">account.invoice</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -1304,17 +1304,17 @@ class account_voucher(osv.osv):
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
message = "%s <b>created</b>." % self._document_type[obj.type or False]
|
message = "%s <b>created</b>." % self._document_type[obj.type or False]
|
||||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||||
|
|
||||||
def post_send_note(self, cr, uid, ids, context=None):
|
def post_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
|
message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
|
||||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||||
|
|
||||||
def reconcile_send_note(self, cr, uid, ids, context=None):
|
def reconcile_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
|
message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
|
||||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||||
|
|
||||||
account_voucher()
|
account_voucher()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
<data noupdate="1">
|
<data noupdate="1">
|
||||||
|
|
||||||
<!-- notify all employees of module installation -->
|
<!-- notify all employees of module installation -->
|
||||||
<record model="mail.message" id="module_install_notification">
|
<record model="mail.message" id="module_install_notification">
|
||||||
<field name="model">mail.group</field>
|
<field name="model">mail.group</field>
|
||||||
|
@ -13,5 +14,12 @@
|
||||||
<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>
|
<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>
|
||||||
]]></field>
|
]]></field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- mail: subtypes -->
|
||||||
|
<record id="mt_voucher" model="mail.message.subtype">
|
||||||
|
<field name="name">Status Change</field>
|
||||||
|
<field name="res_model">account.voucher</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -108,7 +108,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -243,7 +243,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -519,7 +518,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -146,7 +146,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -302,7 +301,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -38,7 +38,8 @@ that have no counterpart in the general financial accounts.
|
||||||
'security/analytic_security.xml',
|
'security/analytic_security.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'analytic_sequence.xml',
|
'analytic_sequence.xml',
|
||||||
'analytic_view.xml'
|
'analytic_view.xml',
|
||||||
|
'analytic_data.xml'
|
||||||
],
|
],
|
||||||
'demo': [],
|
'demo': [],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|
|
@ -284,7 +284,8 @@ class account_analytic_account(osv.osv):
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
|
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name),
|
||||||
|
subtype="analytic.mt_account_status", context=context)
|
||||||
|
|
||||||
account_analytic_account()
|
account_analytic_account()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data noupdate="1">
|
||||||
|
|
||||||
|
<!-- mail: subtypes -->
|
||||||
|
<record id="mt_account_status" model="mail.message.subtype">
|
||||||
|
<field name="name">Status Change</field>
|
||||||
|
<field name="res_model">account.analytic.account</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -53,7 +53,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -223,7 +223,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -359,6 +359,9 @@ class base_stage(object):
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def find_subtype(self, cr, uid, ids, name, context=None):
|
||||||
|
return "mail.mt_comment"
|
||||||
|
|
||||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||||
""" Send a notification when the stage changes. This method has
|
""" Send a notification when the stage changes. This method has
|
||||||
to be overriden, because each document will have its particular
|
to be overriden, because each document will have its particular
|
||||||
|
@ -370,19 +373,22 @@ class base_stage(object):
|
||||||
def case_open_send_note(self, cr, uid, ids, context=None):
|
def case_open_send_note(self, cr, uid, ids, context=None):
|
||||||
for id in ids:
|
for id in ids:
|
||||||
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||||
self.message_post(cr, uid, [id], body=msg, context=context)
|
xml_id = self.find_subtype(cr, uid, ids, context=context)
|
||||||
|
self.message_post(cr, uid, [id], body=msg, subtype=xml_id, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||||
for id in ids:
|
for id in ids:
|
||||||
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||||
self.message_post(cr, uid, [id], body=msg, context=context)
|
xml_id = self.find_subtype(cr, uid, ids, context=context)
|
||||||
|
self.message_post(cr, uid, [id], body=msg, subtype=xml_id, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def case_cancel_send_note(self, cr, uid, ids, context=None):
|
def case_cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
for id in ids:
|
for id in ids:
|
||||||
msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
msg = _('%s has been <b>cancelled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||||
self.message_post(cr, uid, [id], body=msg, context=context)
|
xml_id = self.find_subtype(cr, uid, ids, context=context)
|
||||||
|
self.message_post(cr, uid, [id], body=msg, subtype=xml_id, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def case_pending_send_note(self, cr, uid, ids, context=None):
|
def case_pending_send_note(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -223,7 +223,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -526,7 +525,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -149,7 +149,6 @@
|
||||||
<field name="description" placeholder="Description..."/>
|
<field name="description" placeholder="Description..."/>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -181,7 +181,6 @@
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -95,7 +95,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -167,8 +167,9 @@ class test_message_compose(test_mail.TestMailMockups):
|
||||||
# Test: partner_ids: p_a_id (default) + 3 newly created partners
|
# Test: partner_ids: p_a_id (default) + 3 newly created partners
|
||||||
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids]
|
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids]
|
||||||
message_bird_pids = [partner.id for partner in message_bird.partner_ids]
|
message_bird_pids = [partner.id for partner in message_bird.partner_ids]
|
||||||
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])]) + [p_a_id]
|
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
|
||||||
self.assertEqual(len(message_pigs_pids), len(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
|
self.assertEqual(len(message_pigs_pids), len(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
|
||||||
self.assertEqual(len(message_bird_pids), len(partner_ids), 'mail.message on bird partner_ids incorrect')
|
|
||||||
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
|
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
|
||||||
|
|
||||||
|
self.assertEqual(len(message_bird_pids), len(partner_ids), 'mail.message on bird partner_ids incorrect')
|
||||||
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird partner_ids incorrect')
|
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird partner_ids incorrect')
|
||||||
|
|
|
@ -45,6 +45,7 @@ Key Features
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'wizard/event_confirm_view.xml',
|
'wizard/event_confirm_view.xml',
|
||||||
'event_view.xml',
|
'event_view.xml',
|
||||||
|
'event_data.xml',
|
||||||
'report/report_event_registration_view.xml',
|
'report/report_event_registration_view.xml',
|
||||||
'board_association_view.xml',
|
'board_association_view.xml',
|
||||||
'res_partner_view.xml',
|
'res_partner_view.xml',
|
||||||
|
|
|
@ -360,8 +360,10 @@ class event_registration(osv.osv):
|
||||||
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||||
|
|
||||||
def confirm_registration(self, cr, uid, ids, context=None):
|
def confirm_registration(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_('State set to open'), context=context)
|
for reg in self.browse(cr, uid, ids, context=context or {}):
|
||||||
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
self.pool.get('event.event').message_post(cr, uid, [reg.event_id.id], body=_('New registration confirmed: %s.') % (reg.name or '', ),subtype="event.mt_event_registration", context=context)
|
||||||
|
self.message_post(cr, uid, ids, body=_('Registration confirmed.'), context=context)
|
||||||
|
return self.write(cr, uid, ids, {'state': 'open'},context=context)
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
obj_id = super(event_registration, self).create(cr, uid, vals, context)
|
obj_id = super(event_registration, self).create(cr, uid, vals, context)
|
||||||
|
@ -392,7 +394,7 @@ class event_registration(osv.osv):
|
||||||
self.write(cr, uid, ids, values)
|
self.write(cr, uid, ids, values)
|
||||||
self.message_post(cr, uid, ids, body=_('State set to Done'), context=context)
|
self.message_post(cr, uid, ids, body=_('State set to Done'), context=context)
|
||||||
else:
|
else:
|
||||||
raise osv.except_osv(_('Error!'),_("You must wait for the starting day of the event to do this action.") )
|
raise osv.except_osv(_('Error!'), _("You must wait for the starting day of the event to do this action."))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def button_reg_cancel(self, cr, uid, ids, context=None, *args):
|
def button_reg_cancel(self, cr, uid, ids, context=None, *args):
|
||||||
|
|
|
@ -12,14 +12,19 @@
|
||||||
<field name="state">open</field>
|
<field name="state">open</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- notify all employees of module installation -->
|
<!-- mail: event subtype -->
|
||||||
<record model="mail.message" id="module_install_notification">
|
<record id="event.mt_event_registration" model="mail.message.subtype">
|
||||||
<field name="model">mail.group</field>
|
<field name="name">New Registrations</field>
|
||||||
<field name="res_id" ref="mail.group_all_employees"/>
|
<field name="res_model">event.event</field>
|
||||||
<field name="type">notification</field>
|
<field name="default" eval="False"/>
|
||||||
<field name="subject">Events Organisation application installed!</field>
|
|
||||||
<field name="body">From the top Events menu, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- notify all employees of module installation -->
|
||||||
|
<function model="mail.group" name="message_post">
|
||||||
|
<!-- ids, subject, body, parent_id=False, type='notification', content_subtype='html' -->
|
||||||
|
<value eval="[ref('mail.group_all_employees')]"/>
|
||||||
|
<value>From the top menu Events, you can organize events, manage registrations, automate communication around your event and sell events through your quotations.</value>
|
||||||
|
<value>Module Events has been installed</value>
|
||||||
|
</function>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -196,7 +196,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -479,7 +478,6 @@
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -139,7 +139,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -350,46 +350,43 @@ class hr_holidays(osv.osv):
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
|
|
||||||
def needaction_domain_get(self, cr, uid, ids, context=None):
|
def needaction_domain_get(self, cr, uid, ids, context=None):
|
||||||
# to be tested, otherwise convert into employee_id in ...
|
|
||||||
emp_obj = self.pool.get('hr.employee')
|
emp_obj = self.pool.get('hr.employee')
|
||||||
empids = emp_obj.search(cr, uid, [('parent_id.user_id','=',uid)], context=context)
|
empids = emp_obj.search(cr, uid, [('parent_id.user_id', '=', uid)], context=context)
|
||||||
dom = [
|
dom = ['&', ('state', '=', 'confirm'), ('employee_id', 'in', empids)]
|
||||||
'&', ('state','=','confirm'),('employee_id', 'in', empids)
|
|
||||||
]
|
|
||||||
# if this user is a hr.manager, he should do second validations
|
# if this user is a hr.manager, he should do second validations
|
||||||
if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'):
|
if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'):
|
||||||
dom = ['|'] + dom + [ ('state','=','validate1') ]
|
dom = ['|'] + dom + [('state', '=', 'validate1')]
|
||||||
return dom
|
return dom
|
||||||
|
|
||||||
def create_notificate(self, cr, uid, ids, context=None):
|
def create_notificate(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, ids,
|
self.message_post(cr, uid, ids,
|
||||||
_("The request has been <b>created</b> and is waiting confirmation."), context=context)
|
_("Request <b>created</b>, waiting confirmation."), context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def holidays_confirm_notificate(self, cr, uid, ids, context=None):
|
def holidays_confirm_notificate(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids):
|
for obj in self.browse(cr, uid, ids):
|
||||||
self.message_post(cr, uid, [obj.id],
|
self.message_post(cr, uid, [obj.id],
|
||||||
_("The request has been <b>submitted</b> and is waiting for validation by the manager."), context=context)
|
_("Request <b>submitted</b>, waiting for validation by the manager."), context=context)
|
||||||
|
|
||||||
def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
|
def holidays_first_validate_notificate(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id],
|
self.message_post(cr, uid, [obj.id],
|
||||||
_("The request has been <b>approved</b>. A second validation is necessary and is now pending."), context=context)
|
_("Request <b>approved</b>, waiting second validation."), context=context)
|
||||||
|
|
||||||
def holidays_validate_notificate(self, cr, uid, ids, context=None):
|
def holidays_validate_notificate(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids):
|
for obj in self.browse(cr, uid, ids):
|
||||||
if obj.double_validation:
|
if obj.double_validation:
|
||||||
self.message_post(cr, uid, [obj.id],
|
self.message_post(cr, uid, [obj.id],
|
||||||
_("The request has been <b>double validated</b>. The validation process is now over."), context=context)
|
_("Request <b>validated</b>."), context=context)
|
||||||
else:
|
else:
|
||||||
self.message_post(cr, uid, [obj.id],
|
self.message_post(cr, uid, [obj.id],
|
||||||
_("The request has been <b>approved</b>. The validation process is now over."), context=context)
|
_("The request has been <b>approved</b>."), context=context)
|
||||||
|
|
||||||
def holidays_refuse_notificate(self, cr, uid, ids, context=None):
|
def holidays_refuse_notificate(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids):
|
for obj in self.browse(cr, uid, ids):
|
||||||
self.message_post(cr, uid, [obj.id],
|
self.message_post(cr, uid, [obj.id],
|
||||||
_("The request has been <b>refused</b>. The validation process is now over."), context=context)
|
_("Request <b>refused</b>"), context=context)
|
||||||
|
|
||||||
|
|
||||||
class resource_calendar_leaves(osv.osv):
|
class resource_calendar_leaves(osv.osv):
|
||||||
|
|
|
@ -121,7 +121,6 @@
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,7 +158,6 @@
|
||||||
<field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..."/>
|
<field name="notes" nolabel="1" colspan="4" placeholder="Add a reason..."/>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -461,7 +461,7 @@ class hr_applicant(base_stage, osv.Model):
|
||||||
""" Override of the (void) default notification method. """
|
""" Override of the (void) default notification method. """
|
||||||
if not stage_id: return True
|
if not stage_id: return True
|
||||||
stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||||
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
return self.message_post(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||||
|
|
||||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||||
return 'Applicant'
|
return 'Applicant'
|
||||||
|
@ -474,6 +474,8 @@ class hr_applicant(base_stage, osv.Model):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
for applicant in self.browse(cr, uid, ids, context=context):
|
for applicant in self.browse(cr, uid, ids, context=context):
|
||||||
|
if applicant.job_id:
|
||||||
|
self.pool.get('hr.job').message_post(cr, uid, [applicant.job_id.id], body=_('New employee joined the company %s.')%(applicant.name,), subtype="hr_recruitment.mt_hired", context=context)
|
||||||
if applicant.emp_id:
|
if applicant.emp_id:
|
||||||
message = _("Applicant has been <b>hired</b> and created as an employee.")
|
message = _("Applicant has been <b>hired</b> and created as an employee.")
|
||||||
self.message_post(cr, uid, [applicant.id], body=message, context=context)
|
self.message_post(cr, uid, [applicant.id], body=message, context=context)
|
||||||
|
@ -492,6 +494,9 @@ class hr_applicant(base_stage, osv.Model):
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Applicant has been <b>created</b>.")
|
message = _("Applicant has been <b>created</b>.")
|
||||||
|
for applicant in self.browse(cr, uid, ids, context=context):
|
||||||
|
if applicant.job_id:
|
||||||
|
self.pool.get('hr.job').message_post(cr, uid, [applicant.job_id.id], body=message, subtype="hr_recruitment.mt_applicant_new", context=context)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
return self.message_post(cr, uid, ids, body=message, context=context)
|
||||||
|
|
||||||
class hr_job(osv.osv):
|
class hr_job(osv.osv):
|
||||||
|
|
|
@ -460,6 +460,15 @@ You can automatically receive job application though an email gateway, see the H
|
||||||
<field name="alias_model_id" ref="model_hr_applicant"/>
|
<field name="alias_model_id" ref="model_hr_applicant"/>
|
||||||
<field name="alias_user_id" ref="base.user_root"/>
|
<field name="alias_user_id" ref="base.user_root"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- mail: subtypes -->
|
||||||
|
<record id="mt_hired" model="mail.message.subtype">
|
||||||
|
<field name="name">Employee Hired</field>
|
||||||
|
<field name="res_model">hr.job</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_applicant_new" model="mail.message.subtype">
|
||||||
|
<field name="name">New Applicant</field>
|
||||||
|
<field name="res_model">hr.job</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -183,7 +183,6 @@
|
||||||
<field name="description" placeholder="Feedback of interviews..."/>
|
<field name="description" placeholder="Feedback of interviews..."/>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -85,7 +85,7 @@ class account_analytic_account(osv.osv):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
|
def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
|
||||||
res = super(account_analytic_account,self).on_change_partner_id(cr, uid, ids,partner_id, name, context=context)
|
res = super(account_analytic_account, self).on_change_partner_id(cr, uid, ids, partner_id, name, context=context)
|
||||||
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||||
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
||||||
if pricelist:
|
if pricelist:
|
||||||
|
@ -93,25 +93,25 @@ class account_analytic_account(osv.osv):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def set_close(self, cr, uid, ids, context=None):
|
def set_close(self, cr, uid, ids, context=None):
|
||||||
self.write(cr, uid, ids, {'state':'close'}, context=context)
|
self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||||
message = _("Contract has been <b>closed</b>.")
|
message = _("Contract has been <b>closed</b>.")
|
||||||
self.message_post(cr, uid, ids, body=message, context=context)
|
self.message_post(cr, uid, ids, body=message, subtype="mt_account_closed", context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_cancel(self, cr, uid, ids, context=None):
|
def set_cancel(self, cr, uid, ids, context=None):
|
||||||
self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
|
self.write(cr, uid, ids, {'state': 'cancelled'}, context=context)
|
||||||
message = _("Contract has been <b>cancelled</b>.")
|
message = _("Contract has been <b>canceled</b>.")
|
||||||
self.message_post(cr, uid, ids, body=message, context=context)
|
self.message_post(cr, uid, ids, body=message, subtype="mt_account_canceled", context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_open(self, cr, uid, ids, context=None):
|
def set_open(self, cr, uid, ids, context=None):
|
||||||
self.write(cr, uid, ids, {'state':'open'}, context=context)
|
self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||||
message = _("Contract has been <b>opened</b>.")
|
message = _("Contract has been <b>opened</b>.")
|
||||||
self.message_post(cr, uid, ids, body=message, context=context)
|
self.message_post(cr, uid, ids, body=message, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_pending(self, cr, uid, ids, context=None):
|
def set_pending(self, cr, uid, ids, context=None):
|
||||||
self.write(cr, uid, ids, {'state':'pending'}, context=context)
|
self.write(cr, uid, ids, {'state': 'pending'}, context=context)
|
||||||
message = _("Contract has been set as <b>pending</b>.")
|
message = _("Contract has been set as <b>pending</b>.")
|
||||||
self.message_post(cr, uid, ids, body=message, context=context)
|
self.message_post(cr, uid, ids, body=message, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -71,19 +71,17 @@ class idea_idea(osv.osv):
|
||||||
self.message_post(cr, uid, ids, body=_('Idea canceled.'), context=context)
|
self.message_post(cr, uid, ids, body=_('Idea canceled.'), context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def idea_open(self, cr, uid, ids, context=None):
|
def idea_open(self, cr, uid, ids, context={}):
|
||||||
self.write(cr, uid, ids, { 'state': 'open'})
|
self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||||
self.message_post(cr, uid, ids, body=_('Idea accepted.'), context=context)
|
self.message_post(cr, uid, ids, body=_('Idea accepted.'), context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def idea_close(self, cr, uid, ids, context=None):
|
def idea_close(self, cr, uid, ids, context={}):
|
||||||
self.message_post(cr, uid, ids, body=_('Idea done.'), context=context)
|
self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||||
self.write(cr, uid, ids, { 'state': 'close' })
|
self.message_post(cr, uid, ids, body=_('Idea closed.'), context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def idea_draft(self, cr, uid, ids, context=None):
|
def idea_draft(self, cr, uid, ids, context={}):
|
||||||
|
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||||
self.message_post(cr, uid, ids, body=_('Idea reset to draft.'), context=context)
|
self.message_post(cr, uid, ids, body=_('Idea reset to draft.'), context=context)
|
||||||
self.write(cr, uid, ids, { 'state': 'draft' })
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
idea_idea()
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<record id="base.user_demo" model="res.users">
|
<record id="base.user_demo" model="res.users">
|
||||||
<field name="groups_id" eval="[(4,ref('base.group_tool_user'))]"/>
|
<field name="groups_id" eval="[(4,ref('base.group_tool_user'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,6 @@
|
||||||
<field name="description"/>
|
<field name="description"/>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
import mail_message_subtype
|
||||||
import mail_alias
|
import mail_alias
|
||||||
import mail_followers
|
import mail_followers
|
||||||
import mail_message
|
import mail_message
|
||||||
|
|
|
@ -49,6 +49,7 @@ Main Features
|
||||||
'data': [
|
'data': [
|
||||||
'wizard/invite_view.xml',
|
'wizard/invite_view.xml',
|
||||||
'wizard/mail_compose_message_view.xml',
|
'wizard/mail_compose_message_view.xml',
|
||||||
|
'mail_message_subtype.xml',
|
||||||
'res_config_view.xml',
|
'res_config_view.xml',
|
||||||
'mail_message_view.xml',
|
'mail_message_view.xml',
|
||||||
'mail_mail_view.xml',
|
'mail_mail_view.xml',
|
||||||
|
|
|
@ -12,5 +12,9 @@
|
||||||
<field eval="'process_email_queue'" name="function"/>
|
<field eval="'process_email_queue'" name="function"/>
|
||||||
<field eval="'()'" name="args"/>
|
<field eval="'()'" name="args"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="mt_comment" model="mail.message.subtype">
|
||||||
|
<field name="name">comment</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -11,3 +11,4 @@ Mail Module documentation topics
|
||||||
mail_needaction_howto
|
mail_needaction_howto
|
||||||
mail_partner
|
mail_partner
|
||||||
mail_state
|
mail_state
|
||||||
|
mail_subtype
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
.. _mail_message_subtype:
|
||||||
|
|
||||||
|
OpenChatter Pi (3.1415): Message Subtype
|
||||||
|
========================================
|
||||||
|
|
||||||
|
To overcome the problems of crowdy walls in system notification, We have added features of **Message Subtype** in mail.
|
||||||
|
|
||||||
|
mail.message.subtype
|
||||||
|
++++++++++++++++++++
|
||||||
|
``mail.message.subtype`` has following fields:
|
||||||
|
|
||||||
|
- ``Name``: fields.char(' Message Subtype ', size = 128,required = True,help = 'Subtype Of Message'),
|
||||||
|
- ``model_ids``: fields.many2many('ir.model','mail_message_subtyp_message_rel','message_subtype_id', 'model_id', 'Model',help = "link some subtypes to several models, for projet/task"),
|
||||||
|
- ``default``: fields.boolean('Default', help = "When subscribing to the document, users will receive by default messages related to this subtype unless they uncheck this subtype"),
|
||||||
|
|
||||||
|
mail.followers
|
||||||
|
++++++++++++++
|
||||||
|
|
||||||
|
In ``mail.followers`` we have added additional many2many field subtype ids :
|
||||||
|
|
||||||
|
- ``subtype_ids``: fields.many2many('mail.message.subtype','mail_message_subtyp_rel','subscription_id', 'subtype_id', 'Subtype',help = "linking some subscription to several subtype for projet/task")
|
||||||
|
|
||||||
|
mail.message
|
||||||
|
++++++++++++
|
||||||
|
|
||||||
|
In mail_message we have added additional field subtype_id which Indicates the Type of Message
|
||||||
|
|
||||||
|
- ``subtype_id``: fields.many2one('mail.message.subtype', 'Subtype')
|
||||||
|
|
||||||
|
mail.thread
|
||||||
|
+++++++++++
|
||||||
|
|
||||||
|
- In **message_post** method add the *subtype_id* field as parameter and set as default subtype 'Other'.
|
||||||
|
|
||||||
|
def message_post(self, cr, uid, thread_id, body='', subject=False, msg_type='notification', parent_id=False, attachments=None, subtype='other', context=None, ``**kwargs``):
|
||||||
|
|
||||||
|
- In **message_subscribe** method add the *subtype_ids* field as parameter.In this method if subtype_ids is None, it fatch the default true subtypes in mail.message.subtypes otherwise pass selected subtypes.
|
||||||
|
For update subtypes call **message_subscribe_udpate_subtypes** method
|
||||||
|
|
||||||
|
def message_subscribe(self, cr, uid, ids, partner_ids,subtype_ids = None, context=None):
|
||||||
|
|
||||||
|
- Add **message_subscribe_udpate_subtypes** method to update the subtype_ids in followers.
|
||||||
|
|
||||||
|
def message_subscribe_udpate_subtypes(self, cr, uid, ids, user_id, subtype_ids,context=None):
|
||||||
|
followers_obj = self.pool.get('mail.followers')
|
||||||
|
followers_ids = followers_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)])
|
||||||
|
return followers_obj.write(cr, uid, followers_ids, {'subtype_ids': [(6, 0 , subtype_ids)]}, context = context)
|
||||||
|
|
||||||
|
For Each Addons:
|
||||||
|
++++++++++++++++
|
||||||
|
|
||||||
|
- Add data of subtypes for each addons module.
|
||||||
|
- Add subtype field as parameter in **message_post** Method for each addons module.
|
||||||
|
|
||||||
|
How It Works:
|
||||||
|
+++++++++++++
|
||||||
|
|
||||||
|
- In addons module when we Follow a Perticular document It display under the followers button.
|
||||||
|
- In sybtypes there are 3 default subtypes for each addons
|
||||||
|
1) Email
|
||||||
|
2) Comment
|
||||||
|
3) Other
|
||||||
|
- In document display a default subtypes(which are true) related a perticular model_ids wise.
|
||||||
|
|
||||||
|
Example:-
|
||||||
|
If I have open crm.lead, It display only subtypes of crm.lead
|
||||||
|
|
||||||
|
- When we select subtype it update subtype_ids(which are checked) in mail.follower where match res_model & res_id of the current documents.
|
||||||
|
- when message created update subtype_id of that message in mail.message.
|
||||||
|
- In Feeds display only those notifications of documents which subtypes are selected
|
|
@ -46,6 +46,8 @@ class mail_followers(osv.Model):
|
||||||
help='Id of the followed resource'),
|
help='Id of the followed resource'),
|
||||||
'partner_id': fields.many2one('res.partner', string='Related Partner',
|
'partner_id': fields.many2one('res.partner', string='Related Partner',
|
||||||
ondelete='cascade', required=True, select=1),
|
ondelete='cascade', required=True, select=1),
|
||||||
|
'subtype_ids': fields.many2many('mail.message.subtype', string='Subtype',
|
||||||
|
help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,18 +83,27 @@ class mail_notification(osv.Model):
|
||||||
return super(mail_notification, self).create(cr, uid, vals, context=context)
|
return super(mail_notification, self).create(cr, uid, vals, context=context)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_message_read(self, cr, uid, msg_id, context=None):
|
def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
|
||||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
if msg_ids == None:
|
||||||
notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg_id)], context=context)
|
return False
|
||||||
return self.write(cr, uid, notif_ids, {'read': True}, context=context)
|
if type(msg_ids) is not list:
|
||||||
|
msg_ids=[msg_ids]
|
||||||
|
|
||||||
def get_partners_to_notify(self, cr, uid, partner_ids, message, context=None):
|
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||||
|
notif_ids = self.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', 'in', msg_ids)], context=context)
|
||||||
|
|
||||||
|
return self.write(cr, uid, notif_ids, {'read': read}, context=context)
|
||||||
|
|
||||||
|
def get_partners_to_notify(self, cr, uid, message, context=None):
|
||||||
""" Return the list of partners to notify, based on their preferences.
|
""" Return the list of partners to notify, based on their preferences.
|
||||||
|
|
||||||
:param browse_record message: mail.message to notify
|
:param browse_record message: mail.message to notify
|
||||||
"""
|
"""
|
||||||
notify_pids = []
|
notify_pids = []
|
||||||
for partner in self.pool.get('res.partner').browse(cr, SUPERUSER_ID, partner_ids, context=context):
|
for notification in message.notification_ids:
|
||||||
|
if notification.read:
|
||||||
|
continue
|
||||||
|
partner = notification.partner_id
|
||||||
# Do not send an email to the writer
|
# Do not send an email to the writer
|
||||||
if partner.user_ids and partner.user_ids[0].id == uid:
|
if partner.user_ids and partner.user_ids[0].id == uid:
|
||||||
continue
|
continue
|
||||||
|
@ -111,15 +122,15 @@ class mail_notification(osv.Model):
|
||||||
notify_pids.append(partner.id)
|
notify_pids.append(partner.id)
|
||||||
return notify_pids
|
return notify_pids
|
||||||
|
|
||||||
def notify(self, cr, uid, partner_ids, msg_id, context=None):
|
def _notify(self, cr, uid, msg_id, context=None):
|
||||||
""" Send by email the notification depending on the user preferences """
|
""" Send by email the notification depending on the user preferences """
|
||||||
context = context or {}
|
context = context or {}
|
||||||
# mail_noemail (do not send email) or no partner_ids: do not send, return
|
# mail_noemail (do not send email) or no partner_ids: do not send, return
|
||||||
if context.get('mail_noemail') or not partner_ids:
|
if context.get('mail_noemail'):
|
||||||
return True
|
return True
|
||||||
msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
|
msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context)
|
||||||
|
|
||||||
notify_partner_ids = self.get_partners_to_notify(cr, uid, partner_ids, msg, context=context)
|
notify_partner_ids = self.get_partners_to_notify(cr, uid, msg, context=context)
|
||||||
if not notify_partner_ids:
|
if not notify_partner_ids:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,28 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="view_mail_subscription_form">
|
||||||
|
<field name="name">mail.followers.form</field>
|
||||||
|
<field name="model">mail.followers</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Followers Form" version="7.0">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="res_model"/>
|
||||||
|
<field name="partner_id"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="res_id"/>
|
||||||
|
<field name="subtype_ids" widget="many2many_tags"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<!-- NOTIFICATION !-->
|
<!-- NOTIFICATION !-->
|
||||||
<record model="ir.ui.view" id="view_notification_tree">
|
<record model="ir.ui.view" id="view_notification_tree">
|
||||||
<field name="name">mail.notification.tree</field>
|
<field name="name">mail.notification.tree</field>
|
||||||
|
|
|
@ -30,6 +30,7 @@ class mail_group(osv.Model):
|
||||||
group. The group mechanics are based on the followers. """
|
group. The group mechanics are based on the followers. """
|
||||||
_description = 'Discussion group'
|
_description = 'Discussion group'
|
||||||
_name = 'mail.group'
|
_name = 'mail.group'
|
||||||
|
_mail_autothread = False
|
||||||
_inherit = ['mail.thread']
|
_inherit = ['mail.thread']
|
||||||
_inherits = {'mail.alias': 'alias_id', 'ir.ui.menu': 'menu_id'}
|
_inherits = {'mail.alias': 'alias_id', 'ir.ui.menu': 'menu_id'}
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ class mail_group(osv.Model):
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
result = super(mail_group, self).write(cr, uid, ids, vals, context=context)
|
result = super(mail_group, self).write(cr, uid, ids, vals, context=context)
|
||||||
if vals.get('group_ids'):
|
if vals.get('group_ids'):
|
||||||
self._subscribe_users(cr, uid, ids, vals.get('group_ids'), context=context)
|
self._subscribe_users(cr, uid, ids, context=context)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def action_follow(self, cr, uid, ids, context=None):
|
def action_follow(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
<field name="priority" eval="10"/>
|
<field name="priority" eval="10"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<kanban>
|
<kanban>
|
||||||
<field name="message_is_follower"/>
|
|
||||||
<field name="message_follower_ids"/>
|
<field name="message_follower_ids"/>
|
||||||
|
<field name="message_is_follower"/>
|
||||||
<field name="message_summary"/>
|
<field name="message_summary"/>
|
||||||
|
<field name="description"/>
|
||||||
<templates>
|
<templates>
|
||||||
<t t-name="kanban-description">
|
<t t-name="kanban-description">
|
||||||
<div class="oe_group_description" t-if="record.description.raw_value">
|
<div class="oe_group_description" t-if="record.description.raw_value">
|
||||||
|
@ -81,7 +82,6 @@
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"
|
<field name="message_ids" widget="mail_thread"
|
||||||
options='{"thread_level": 1}'/>
|
options='{"thread_level": 1}'/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
|
|
|
@ -131,6 +131,7 @@ class mail_message(osv.Model):
|
||||||
'unread': fields.function(_get_unread, fnct_search=_search_unread,
|
'unread': fields.function(_get_unread, fnct_search=_search_unread,
|
||||||
type='boolean', string='Unread',
|
type='boolean', string='Unread',
|
||||||
help='Functional field to search for unread messages linked to uid'),
|
help='Functional field to search for unread messages linked to uid'),
|
||||||
|
'subtype_id': fields.many2one('mail.message.subtype', 'Subtype'),
|
||||||
'vote_user_ids': fields.many2many('res.users', 'mail_vote', 'message_id', 'user_id', string='Votes',
|
'vote_user_ids': fields.many2many('res.users', 'mail_vote', 'message_id', 'user_id', string='Votes',
|
||||||
help='Users that voted for this message'),
|
help='Users that voted for this message'),
|
||||||
}
|
}
|
||||||
|
@ -167,7 +168,7 @@ class mail_message(osv.Model):
|
||||||
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
|
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, user_id)]}, context=context)
|
||||||
else:
|
else:
|
||||||
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
|
self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, user_id)]}, context=context)
|
||||||
return True
|
return not(has_voted) or False
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Message loading for web interface
|
# Message loading for web interface
|
||||||
|
@ -179,6 +180,7 @@ class mail_message(osv.Model):
|
||||||
fields allow to have the foreign record name without having
|
fields allow to have the foreign record name without having
|
||||||
to check external access rights).
|
to check external access rights).
|
||||||
"""
|
"""
|
||||||
|
child_nbr = len(msg.child_ids)
|
||||||
has_voted = False
|
has_voted = False
|
||||||
vote_ids = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [user.id for user in msg.vote_user_ids], context=context)
|
vote_ids = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [user.id for user in msg.vote_user_ids], context=context)
|
||||||
for vote in vote_ids:
|
for vote in vote_ids:
|
||||||
|
@ -191,7 +193,7 @@ class mail_message(osv.Model):
|
||||||
attachment_ids = []
|
attachment_ids = []
|
||||||
try:
|
try:
|
||||||
author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
|
author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
|
||||||
is_author = uid in msg.author_id.user_ids
|
is_author = uid == msg.author_id.user_ids[0].id
|
||||||
except (orm.except_orm, osv.except_osv):
|
except (orm.except_orm, osv.except_osv):
|
||||||
author_id = False
|
author_id = False
|
||||||
is_author = False
|
is_author = False
|
||||||
|
@ -199,6 +201,7 @@ class mail_message(osv.Model):
|
||||||
partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
|
partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
|
||||||
except (orm.except_orm, osv.except_osv):
|
except (orm.except_orm, osv.except_osv):
|
||||||
partner_ids = []
|
partner_ids = []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': msg.id,
|
'id': msg.id,
|
||||||
'type': msg.type,
|
'type': msg.type,
|
||||||
|
@ -212,12 +215,30 @@ class mail_message(osv.Model):
|
||||||
'author_id': author_id,
|
'author_id': author_id,
|
||||||
'is_author': is_author,
|
'is_author': is_author,
|
||||||
'partner_ids': partner_ids,
|
'partner_ids': partner_ids,
|
||||||
'child_ids': [],
|
'parent_id': msg.parent_id and msg.parent_id.id or False,
|
||||||
'vote_user_ids': vote_ids,
|
'vote_user_ids': vote_ids,
|
||||||
'has_voted': has_voted
|
'has_voted': has_voted,
|
||||||
|
'unread': msg.unread and msg.unread['unread'] or False
|
||||||
}
|
}
|
||||||
|
|
||||||
def message_read_tree_flatten(self, cr, uid, messages, current_level, level, context=None):
|
def message_read_tree_get_expandable(self, cr, uid, parent_message, last_message, domain=[], current_level=0, level=0, context=None):
|
||||||
|
""" . """
|
||||||
|
base_domain = [('id', '<', last_message['id'])]
|
||||||
|
if parent_message and current_level < level:
|
||||||
|
base_domain += [('parent_id', '=', parent_message['id'])]
|
||||||
|
elif parent_message:
|
||||||
|
base_domain += [('id', 'child_of', parent_message['id']), ('id', '!=', parent_message['id'])]
|
||||||
|
if domain:
|
||||||
|
base_domain += domain
|
||||||
|
extension = { 'type': 'expandable',
|
||||||
|
'domain': base_domain,
|
||||||
|
'thread_level': current_level,
|
||||||
|
'context': context,
|
||||||
|
'id': -1,
|
||||||
|
}
|
||||||
|
return extension
|
||||||
|
|
||||||
|
def message_read_tree_flatten(self, cr, uid, parent_message, messages, domain=[], level=0, current_level=0, context=None, limit=None, add_expandable=True):
|
||||||
""" Given a tree with several roots of following structure :
|
""" Given a tree with several roots of following structure :
|
||||||
[ {'id': 1, 'child_ids': [
|
[ {'id': 1, 'child_ids': [
|
||||||
{'id': 11, 'child_ids': [...] },],
|
{'id': 11, 'child_ids': [...] },],
|
||||||
|
@ -236,69 +257,143 @@ class mail_message(osv.Model):
|
||||||
child_ids = msg_dict.pop('child_ids', [])
|
child_ids = msg_dict.pop('child_ids', [])
|
||||||
msg_dict['child_ids'] = []
|
msg_dict['child_ids'] = []
|
||||||
return [msg_dict] + child_ids
|
return [msg_dict] + child_ids
|
||||||
# return sorted([msg_dict] + child_ids, key=itemgetter('id'), reverse=True)
|
|
||||||
context = context or {}
|
context = context or {}
|
||||||
|
limit = limit or self._message_read_limit
|
||||||
|
|
||||||
# Depth-first flattening
|
# Depth-first flattening
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if message.get('type') == 'expandable':
|
if message.get('type') == 'expandable':
|
||||||
continue
|
continue
|
||||||
message['child_ids'] = self.message_read_tree_flatten(cr, uid, message['child_ids'], current_level + 1, level, context=context)
|
message['child_ids'] = self.message_read_tree_flatten(cr, uid, message, message['child_ids'], domain, level, current_level + 1, context=context, limit=limit)
|
||||||
|
for child in message['child_ids']:
|
||||||
|
if child.get('type') == 'expandable':
|
||||||
|
continue
|
||||||
|
message['child_nbr'] += child['child_nbr']
|
||||||
# Flatten if above maximum depth
|
# Flatten if above maximum depth
|
||||||
if current_level < level:
|
if current_level < level:
|
||||||
return_list = messages
|
return_list = messages
|
||||||
else:
|
else:
|
||||||
return_list = []
|
return_list = [flat_message for message in messages for flat_message in _flatten(message)]
|
||||||
for message in messages:
|
|
||||||
for flat_message in _flatten(message):
|
|
||||||
return_list.append(flat_message)
|
|
||||||
return sorted(return_list, key=itemgetter(context.get('sort_key', 'id')), reverse=context.get('sort_reverse', True))
|
|
||||||
|
|
||||||
def message_read(self, cr, uid, ids=False, domain=[], thread_level=0, limit=None, context=None):
|
# Add expandable
|
||||||
""" If IDs are provided, fetch these records. Otherwise use the domain
|
return_list = sorted(return_list, key=itemgetter(context.get('sort_key', 'id')), reverse=context.get('sort_reverse', True))
|
||||||
to fetch the matching records.
|
if return_list and current_level == 0 and add_expandable:
|
||||||
After having fetched the records provided by IDs, it will fetch the
|
expandable = self.message_read_tree_get_expandable(cr, uid, parent_message, return_list and return_list[-1] or parent_message, domain, current_level, level, context=context)
|
||||||
parents to have well-formed threads.
|
return_list.append(expandable)
|
||||||
|
elif return_list and current_level <= level and add_expandable:
|
||||||
|
expandable = self.message_read_tree_get_expandable(cr, uid, parent_message, return_list and return_list[-1] or parent_message, domain, current_level, level, context=context)
|
||||||
|
return_list.append(expandable)
|
||||||
|
return return_list
|
||||||
|
|
||||||
|
def message_read(self, cr, uid, ids=False, domain=[], level=0, context=None, parent_id=False, limit=None):
|
||||||
|
""" Read messages from mail.message, and get back a structured tree
|
||||||
|
of messages to be displayed as discussion threads. If IDs is set,
|
||||||
|
fetch these records. Otherwise use the domain to fetch messages.
|
||||||
|
After having fetch messages, their parents will be added to obtain
|
||||||
|
well formed threads.
|
||||||
|
|
||||||
|
:param domain: optional domain for searching ids
|
||||||
|
:param level: level of threads to display, 0 being flat
|
||||||
|
:param limit: number of messages to fetch
|
||||||
|
:param parent_id: if parent_id reached, stop searching for
|
||||||
|
further parents
|
||||||
:return list: list of trees of messages
|
:return list: list of trees of messages
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
message_loaded = context and context.get('message_loaded') or [0]
|
||||||
|
|
||||||
|
# don't read the message display by .js, in context message_loaded list
|
||||||
|
if context and context.get('message_loaded'):
|
||||||
|
domain += [ ['id','not in',message_loaded] ];
|
||||||
|
|
||||||
limit = limit or self._message_read_limit
|
limit = limit or self._message_read_limit
|
||||||
context = context or {}
|
context = context or {}
|
||||||
if not ids:
|
|
||||||
ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
|
|
||||||
messages = self.browse(cr, uid, ids, context=context)
|
|
||||||
|
|
||||||
|
tree = []
|
||||||
result = []
|
result = []
|
||||||
tree = {} # key: ID, value: record
|
record = None
|
||||||
for msg in messages:
|
|
||||||
if len(result) < (limit - 1):
|
# select ids
|
||||||
record = self._message_dict_get(cr, uid, msg, context=context)
|
if ids:
|
||||||
if thread_level and msg.parent_id:
|
for msg in self.browse(cr, uid, ids, context=context):
|
||||||
while msg.parent_id:
|
result.append(self._message_dict_get(cr, uid, msg, context=context))
|
||||||
if msg.parent_id.id in tree:
|
return result
|
||||||
record_parent = tree[msg.parent_id.id]
|
|
||||||
else:
|
# key: ID, value: record
|
||||||
record_parent = self._message_dict_get(cr, uid, msg.parent_id, context=context)
|
ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
|
||||||
if msg.parent_id.parent_id:
|
for msg in self.browse(cr, uid, ids, context=context):
|
||||||
tree[msg.parent_id.id] = record_parent
|
# if not in record and not in message_loded list
|
||||||
if record['id'] not in [x['id'] for x in record_parent['child_ids']]:
|
if msg.id not in tree and msg.id not in message_loaded :
|
||||||
record_parent['child_ids'].append(record)
|
record = self._message_dict_get(cr, uid, msg, context=context)
|
||||||
record = record_parent
|
tree.append(msg.id)
|
||||||
msg = msg.parent_id
|
result.append(record)
|
||||||
if msg.id not in tree:
|
|
||||||
result.append(record)
|
while msg.parent_id and msg.parent_id.id != parent_id:
|
||||||
tree[msg.id] = record
|
parent_id = msg.parent_id.id
|
||||||
else:
|
if msg.parent_id.id not in tree:
|
||||||
result.append({
|
msg = msg.parent_id
|
||||||
'type': 'expandable',
|
tree.append(msg.id)
|
||||||
'domain': [('id', '<=', msg.id)] + domain,
|
# if not in record and not in message_loded list
|
||||||
'context': context,
|
if msg.id not in message_loaded :
|
||||||
'thread_level': thread_level, # should be improve accodting to level of records
|
record = self._message_dict_get(cr, uid, msg, context=context)
|
||||||
'id': -1,
|
result.append(record)
|
||||||
})
|
|
||||||
break
|
result = sorted(result, key=lambda k: k['id'])
|
||||||
|
|
||||||
|
|
||||||
|
tree_not = []
|
||||||
|
# expandable for not show message
|
||||||
|
for id_msg in tree:
|
||||||
|
# get all childs
|
||||||
|
not_loaded_ids = self.search(cr, SUPERUSER_ID, [['parent_id','=',id_msg],['id','not in',message_loaded]], None, limit=1000)
|
||||||
|
# group childs not read
|
||||||
|
id_min=None
|
||||||
|
id_max=None
|
||||||
|
nb=0
|
||||||
|
for not_loaded_id in not_loaded_ids:
|
||||||
|
if not_loaded_id not in tree:
|
||||||
|
nb+=1
|
||||||
|
if id_min==None or id_min>not_loaded_id:
|
||||||
|
id_min=not_loaded_id
|
||||||
|
if id_max==None or id_max<not_loaded_id:
|
||||||
|
id_max=not_loaded_id
|
||||||
|
tree_not.append(not_loaded_id)
|
||||||
|
else:
|
||||||
|
if nb>0:
|
||||||
|
result.append({
|
||||||
|
'domain': [['id','>=',id_min],['id','<=',id_max],['parent_id','=',id_msg]],
|
||||||
|
'nb_messages': nb,
|
||||||
|
'type': 'expandable',
|
||||||
|
'parent_id': id_msg,
|
||||||
|
'id': id_min
|
||||||
|
})
|
||||||
|
nb=0
|
||||||
|
if nb>0:
|
||||||
|
result.append({
|
||||||
|
'domain': [['id','>=',id_min],['parent_id','=',id_msg]],
|
||||||
|
'nb_messages': nb,
|
||||||
|
'type': 'expandable',
|
||||||
|
'parent_id': id_msg,
|
||||||
|
'id': id_min
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# expandable for limit max
|
||||||
|
ids = self.search(cr, SUPERUSER_ID, domain+[['id','not in',message_loaded+tree+tree_not]], context=context, limit=1)
|
||||||
|
if len(ids) > 0:
|
||||||
|
result.append(
|
||||||
|
{
|
||||||
|
'domain': domain,
|
||||||
|
'nb_messages': 0,
|
||||||
|
'type': 'expandable',
|
||||||
|
'parent_id': parent_id,
|
||||||
|
'id': -1
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
result = sorted(result, key=lambda k: k['id'])
|
||||||
|
|
||||||
# Flatten the result
|
|
||||||
if thread_level > 0:
|
|
||||||
result = self.message_read_tree_flatten(cr, uid, result, 0, thread_level, context=context)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
|
@ -409,7 +504,7 @@ class mail_message(osv.Model):
|
||||||
if not values.get('message_id') and values.get('res_id') and values.get('model'):
|
if not values.get('message_id') and values.get('res_id') and values.get('model'):
|
||||||
values['message_id'] = tools.generate_tracking_message_id('%(model)s-%(res_id)s' % values)
|
values['message_id'] = tools.generate_tracking_message_id('%(model)s-%(res_id)s' % values)
|
||||||
newid = super(mail_message, self).create(cr, uid, values, context)
|
newid = super(mail_message, self).create(cr, uid, values, context)
|
||||||
self.notify(cr, uid, newid, context=context)
|
self._notify(cr, 1, newid, context=context)
|
||||||
return newid
|
return newid
|
||||||
|
|
||||||
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
|
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
|
||||||
|
@ -431,26 +526,39 @@ class mail_message(osv.Model):
|
||||||
self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context)
|
self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context)
|
||||||
return super(mail_message, self).unlink(cr, uid, ids, context=context)
|
return super(mail_message, self).unlink(cr, uid, ids, context=context)
|
||||||
|
|
||||||
def notify(self, cr, uid, newid, context=None):
|
def _notify(self, cr, uid, newid, context=None):
|
||||||
""" Add the related record followers to the destination partner_ids.
|
""" Add the related record followers to the destination partner_ids.
|
||||||
Call mail_notification.notify to manage the email sending
|
Call mail_notification.notify to manage the email sending
|
||||||
"""
|
"""
|
||||||
message = self.browse(cr, uid, newid, context=context)
|
message = self.browse(cr, uid, newid, context=context)
|
||||||
partners_to_notify = set([])
|
partners_to_notify = set([])
|
||||||
# add all partner_ids of the message
|
# message has no subtype_id: pure log message -> no partners, no one notified
|
||||||
|
if not message.subtype_id:
|
||||||
|
message.write({'partner_ids': [5]})
|
||||||
|
return True
|
||||||
|
# all partner_ids of the mail.message have to be notified
|
||||||
if message.partner_ids:
|
if message.partner_ids:
|
||||||
partners_to_notify |= set(partner.id for partner in message.partner_ids)
|
partners_to_notify |= set(partner.id for partner in message.partner_ids)
|
||||||
# add all followers and set add them in partner_ids
|
# all followers of the mail.message document have to be added as partners and notified
|
||||||
if message.model and message.res_id:
|
if message.model and message.res_id:
|
||||||
record = self.pool.get(message.model).browse(cr, SUPERUSER_ID, message.res_id, context=context)
|
fol_obj = self.pool.get("mail.followers")
|
||||||
extra_notified = set(partner.id for partner in record.message_follower_ids)
|
fol_ids = fol_obj.search(cr, uid, [('res_model', '=', message.model), ('res_id', '=', message.res_id), ('subtype_ids', 'in', message.subtype_id.id)], context=context)
|
||||||
|
fol_objs = fol_obj.browse(cr, uid, fol_ids, context=context)
|
||||||
|
extra_notified = set(fol.partner_id.id for fol in fol_objs)
|
||||||
missing_notified = extra_notified - partners_to_notify
|
missing_notified = extra_notified - partners_to_notify
|
||||||
|
missing_notified = missing_notified
|
||||||
if missing_notified:
|
if missing_notified:
|
||||||
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
|
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
|
||||||
partners_to_notify |= extra_notified
|
partners_to_notify |= extra_notified
|
||||||
# # remove uid from partners
|
|
||||||
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, uid)]}, context=context)
|
# add myself if I wrote on my wall,
|
||||||
self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context)
|
# unless remove myself author
|
||||||
|
if ((message.model=="res.partner" and message.res_id==message.author_id.id)):
|
||||||
|
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, message.author_id.id)]}, context=context)
|
||||||
|
else:
|
||||||
|
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, message.author_id.id)]}, context=context)
|
||||||
|
|
||||||
|
self.pool.get('mail.notification')._notify(cr, uid, newid, context=context)
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
"""Overridden to avoid duplicating fields that are unique to each email"""
|
"""Overridden to avoid duplicating fields that are unique to each email"""
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# Copyright (C) 2012-today OpenERP SA (<http://www.openerp.com>)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
from osv import osv
|
||||||
|
from osv import fields
|
||||||
|
|
||||||
|
|
||||||
|
class mail_message_subtype(osv.osv):
|
||||||
|
""" Class holding subtype definition for messages. Subtypes allow to tune
|
||||||
|
the follower subscription, allowing only some subtypes to be pushed
|
||||||
|
on the Wall. """
|
||||||
|
_name = 'mail.message.subtype'
|
||||||
|
_description = 'mail_message_subtype'
|
||||||
|
_columns = {
|
||||||
|
'name': fields.char('Message Type', required=True, translate=True,
|
||||||
|
help='Message subtype, gives a more precise type on the message, '\
|
||||||
|
'especially for system notifications. For example, it can be '\
|
||||||
|
'a notification related to a new record (New), or to a stage '\
|
||||||
|
'change in a process (Stage change). Message subtypes allow to '\
|
||||||
|
'precisely tune the notifications the user want to receive on its wall.'),
|
||||||
|
'res_model': fields.char('Model', help="link subtype to model"),
|
||||||
|
'default': fields.boolean('Default',
|
||||||
|
help="When subscribing to the document, this subtype will be checked by default."),
|
||||||
|
}
|
||||||
|
_defaults = {
|
||||||
|
'default': True,
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="view_message_subtype_tree">
|
||||||
|
<field name="name">mail.message.subtype.tree</field>
|
||||||
|
<field name="model">mail.message.subtype</field>
|
||||||
|
<field name="priority">10</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Subtype">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="res_model"/>
|
||||||
|
<field name="default"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="view_mail_message_subtype_form">
|
||||||
|
<field name="name">mail.message.subtype.form</field>
|
||||||
|
<field name="model">mail.message.subtype</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Email message" version="7.0">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="res_model"/>
|
||||||
|
<field name="default"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.actions.act_window" id="action_view_message_subtype">
|
||||||
|
<field name="name">Subtypes</field>
|
||||||
|
<field name="res_model">mail.message.subtype</field>
|
||||||
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
</record>
|
||||||
|
<menuitem name="Subtypes" id="menu_message_subtype" parent="base.menu_email" action="action_view_message_subtype"/>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -31,6 +31,7 @@
|
||||||
<field name="author_id"/>
|
<field name="author_id"/>
|
||||||
<field name="date"/>
|
<field name="date"/>
|
||||||
<field name="type"/>
|
<field name="type"/>
|
||||||
|
<field name="subtype_id"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="model"/>
|
<field name="model"/>
|
||||||
|
@ -55,16 +56,18 @@
|
||||||
<field name="subject" string="Content" filter_domain="['|', ('subject', 'ilike', self), ('body', 'ilike', self)]" />
|
<field name="subject" string="Content" filter_domain="['|', ('subject', 'ilike', self), ('body', 'ilike', self)]" />
|
||||||
<field name="type"/>
|
<field name="type"/>
|
||||||
<field name="author_id"/>
|
<field name="author_id"/>
|
||||||
<filter icon="terp-personal+" string="Comments"
|
<filter string="Unread"
|
||||||
|
name="unread_message" help="Show unread message"
|
||||||
|
domain="[('unread', '=', True)]"/>
|
||||||
|
<filter string="Comments"
|
||||||
name="comments" help="Comments"
|
name="comments" help="Comments"
|
||||||
domain="[('type', '=', 'comment')]"/>
|
domain="[('type', '=', 'comment')]"/>
|
||||||
<filter icon="terp-personal+" string="Notifications"
|
<filter string="Notifications"
|
||||||
name="notifications" help="Notifications"
|
name="notifications" help="Notifications"
|
||||||
domain="[('type', '=', 'notification')]"/>
|
domain="[('type', '=', 'notification')]"/>
|
||||||
<filter icon="terp-personal+" string="Emails"
|
<filter string="Emails"
|
||||||
name="emails" help="Emails"
|
name="emails" help="Emails"
|
||||||
domain="[('type', '=', 'email')]"/>
|
domain="[('type', '=', 'email')]"/>
|
||||||
<field name="author_id"/>
|
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
@ -75,20 +78,28 @@
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="search_view_id" ref="view_message_search"/>
|
<field name="search_view_id" ref="view_message_search"/>
|
||||||
|
<field name="context">{'search_default_unread_message':True}</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Add menu entry in Settings/Email -->
|
<!-- Add menu entry in Settings/Email -->
|
||||||
<menuitem name="Messages" id="menu_mail_message" parent="base.menu_email" action="action_view_mail_message"/>
|
<menuitem name="Messages" id="menu_mail_message" parent="base.menu_email" action="action_view_mail_message"/>
|
||||||
|
|
||||||
<record id="action_mail_all_feeds" model="ir.actions.client">
|
<record id="action_mail_inbox_feeds" model="ir.actions.client">
|
||||||
<field name="name">News Feed</field>
|
<field name="name">Inbox</field>
|
||||||
<field name="tag">mail.wall</field>
|
<field name="tag">mail.wall</field>
|
||||||
<field name="params" eval=""{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid])],
|
<field name="params" eval=""{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', True)],
|
||||||
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="action_mail_my_feeds" model="ir.actions.client">
|
<record id="action_mail_archives_feeds" model="ir.actions.client">
|
||||||
<field name="name">My Posts</field>
|
<field name="name">Archives</field>
|
||||||
|
<field name="tag">mail.wall</field>
|
||||||
|
<field name="params" eval=""{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', False)],
|
||||||
|
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_mail_sent_feeds" model="ir.actions.client">
|
||||||
|
<field name="name">Sent</field>
|
||||||
<field name="tag">mail.wall</field>
|
<field name="tag">mail.wall</field>
|
||||||
<field name="params" eval=""{'domain': [('author_id.user_ids', 'in', [uid])],
|
<field name="params" eval=""{'domain': [('author_id.user_ids', 'in', [uid])],
|
||||||
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
'context': {'default_model': 'res.users', 'default_res_id': uid} }""/>
|
||||||
|
|
|
@ -96,6 +96,7 @@ class many2many_reference(fields.many2many):
|
||||||
else:
|
else:
|
||||||
return super(many2many_reference, self).set(cr, model, id, name, values, user, context)
|
return super(many2many_reference, self).set(cr, model, id, name, values, user, context)
|
||||||
|
|
||||||
|
|
||||||
class mail_thread(osv.AbstractModel):
|
class mail_thread(osv.AbstractModel):
|
||||||
''' mail_thread model is meant to be inherited by any model that needs to
|
''' mail_thread model is meant to be inherited by any model that needs to
|
||||||
act as a discussion topic on which messages can be attached. Public
|
act as a discussion topic on which messages can be attached. Public
|
||||||
|
@ -116,10 +117,13 @@ class mail_thread(osv.AbstractModel):
|
||||||
'''
|
'''
|
||||||
_name = 'mail.thread'
|
_name = 'mail.thread'
|
||||||
_description = 'Email Thread'
|
_description = 'Email Thread'
|
||||||
|
_mail_autothread = True
|
||||||
|
|
||||||
def _get_message_data(self, cr, uid, ids, name, args, context=None):
|
def _get_message_data(self, cr, uid, ids, name, args, context=None):
|
||||||
|
""" Computes:
|
||||||
|
- message_unread: has uid unread message for the document
|
||||||
|
- message_summary: html snippet summarizing the Chatter for kanban views """
|
||||||
res = dict((id, dict(message_unread=False, message_summary='')) for id in ids)
|
res = dict((id, dict(message_unread=False, message_summary='')) for id in ids)
|
||||||
partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
|
||||||
|
|
||||||
# search for unread messages, by reading directly mail.notification, as SUPERUSER
|
# search for unread messages, by reading directly mail.notification, as SUPERUSER
|
||||||
notif_obj = self.pool.get('mail.notification')
|
notif_obj = self.pool.get('mail.notification')
|
||||||
|
@ -132,10 +136,41 @@ class mail_thread(osv.AbstractModel):
|
||||||
for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context):
|
for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context):
|
||||||
res[notif.message_id.res_id]['message_unread'] = True
|
res[notif.message_id.res_id]['message_unread'] = True
|
||||||
|
|
||||||
for thread in self.read(cr, uid, ids, ['message_follower_ids', 'message_comment_ids', 'message_ids'], context=context):
|
for thread in self.browse(cr, uid, ids, context=context):
|
||||||
cls = res[thread['id']]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
|
cls = res[thread.id]['message_unread'] and ' class="oe_kanban_mail_new"' or ''
|
||||||
res[thread['id']]['message_summary'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (cls, len(thread['message_comment_ids']), len(thread['message_follower_ids']))
|
res[thread.id]['message_summary'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids))
|
||||||
res[thread['id']]['message_is_follower'] = partner_id in thread['message_follower_ids']
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _get_subscription_data(self, cr, uid, ids, name, args, context=None):
|
||||||
|
""" Computes:
|
||||||
|
- message_is_follower: is uid in the document followers
|
||||||
|
- message_subtype_data: data about document subtypes: which are
|
||||||
|
available, which are followed if any """
|
||||||
|
res = dict((id, dict(message_subtype_data='', message_is_follower=False)) for id in ids)
|
||||||
|
user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||||
|
|
||||||
|
# find current model subtypes, add them to a dictionary
|
||||||
|
subtype_obj = self.pool.get('mail.message.subtype')
|
||||||
|
subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context)
|
||||||
|
subtype_dict = dict((subtype.name, dict(default=subtype.default, followed=False, id=subtype.id)) for subtype in subtype_obj.browse(cr, uid, subtype_ids, context=context))
|
||||||
|
for id in ids:
|
||||||
|
res[id]['message_subtype_data'] = subtype_dict.copy()
|
||||||
|
|
||||||
|
# find the document followers, update the data
|
||||||
|
fol_obj = self.pool.get('mail.followers')
|
||||||
|
fol_ids = fol_obj.search(cr, uid, [
|
||||||
|
('partner_id', '=', user_pid),
|
||||||
|
('res_id', 'in', ids),
|
||||||
|
('res_model', '=', self._name),
|
||||||
|
], context=context)
|
||||||
|
for fol in fol_obj.browse(cr, uid, fol_ids, context=context):
|
||||||
|
thread_subtype_dict = res[fol.res_id]['message_subtype_data']
|
||||||
|
res[fol.res_id]['message_is_follower'] = True
|
||||||
|
for subtype in fol.subtype_ids:
|
||||||
|
thread_subtype_dict[subtype.name]['followed'] = True
|
||||||
|
res[fol.res_id]['message_subtype_data'] = thread_subtype_dict
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None):
|
def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None):
|
||||||
|
@ -152,8 +187,13 @@ class mail_thread(osv.AbstractModel):
|
||||||
return [('id', 'in', res.keys())]
|
return [('id', 'in', res.keys())]
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'message_is_follower': fields.function(_get_message_data,
|
'message_is_follower': fields.function(_get_subscription_data,
|
||||||
type='boolean', string='Is a Follower', multi='_get_message_data'),
|
type='boolean', string='Is a Follower', multi='_get_subscription_data,'),
|
||||||
|
'message_subtype_data': fields.function(_get_subscription_data,
|
||||||
|
type='text', string='Subscription data', multi="_get_subscription_data",
|
||||||
|
help="Holds data about the subtypes. The content of this field "\
|
||||||
|
"is a structure holding the current model subtypes, and the "\
|
||||||
|
"current document followed subtypes."),
|
||||||
'message_follower_ids': many2many_reference('res.partner',
|
'message_follower_ids': many2many_reference('res.partner',
|
||||||
'mail_followers', 'res_id', 'partner_id',
|
'mail_followers', 'res_id', 'partner_id',
|
||||||
reference_column='res_model', string='Followers'),
|
reference_column='res_model', string='Followers'),
|
||||||
|
@ -571,12 +611,12 @@ class mail_thread(osv.AbstractModel):
|
||||||
"now deprecated res.log.")
|
"now deprecated res.log.")
|
||||||
self.message_post(cr, uid, [id], message, context=context)
|
self.message_post(cr, uid, [id], message, context=context)
|
||||||
|
|
||||||
def message_post(self, cr, uid, thread_id, body='', subject=False,
|
def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
|
||||||
type='notification', parent_id=False, attachments=None, context=None, **kwargs):
|
subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
|
||||||
""" Post a new message in an existing thread, returning the new
|
""" Post a new message in an existing thread, returning the new
|
||||||
mail.message ID. Extra keyword arguments will be used as default
|
mail.message ID. Extra keyword arguments will be used as default
|
||||||
column values for the new mail.message record.
|
column values for the new mail.message record.
|
||||||
|
Auto link messages for same id and object
|
||||||
:param int thread_id: thread ID to post into, or list with one ID
|
:param int thread_id: thread ID to post into, or list with one ID
|
||||||
:param str body: body of the message, usually raw HTML that will
|
:param str body: body of the message, usually raw HTML that will
|
||||||
be sanitized
|
be sanitized
|
||||||
|
@ -587,9 +627,10 @@ class mail_thread(osv.AbstractModel):
|
||||||
``(name,content)``, where content is NOT base64 encoded
|
``(name,content)``, where content is NOT base64 encoded
|
||||||
:return: ID of newly created mail.message
|
:return: ID of newly created mail.message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
context = context or {}
|
context = context or {}
|
||||||
attachments = attachments or []
|
attachments = attachments or []
|
||||||
assert (not thread_id) or isinstance(thread_id, (int,long)) or \
|
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
|
||||||
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
|
(isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
|
||||||
if isinstance(thread_id, (list, tuple)):
|
if isinstance(thread_id, (list, tuple)):
|
||||||
thread_id = thread_id and thread_id[0]
|
thread_id = thread_id and thread_id[0]
|
||||||
|
@ -608,39 +649,86 @@ class mail_thread(osv.AbstractModel):
|
||||||
}
|
}
|
||||||
attachment_ids.append((0, 0, data_attach))
|
attachment_ids.append((0, 0, data_attach))
|
||||||
|
|
||||||
|
# get subtype
|
||||||
|
if not subtype:
|
||||||
|
subtype = 'mail.mt_comment'
|
||||||
|
s = subtype.split('.')
|
||||||
|
if len(s)==1:
|
||||||
|
s = ('mail', s[0])
|
||||||
|
ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s[0], s[1])
|
||||||
|
subtype_id = ref and ref[1] or False
|
||||||
|
|
||||||
|
model = context.get('thread_model', self._name) if thread_id else False
|
||||||
|
messages = self.pool.get('mail.message')
|
||||||
|
|
||||||
|
#auto link messages for same id and object
|
||||||
|
if self._mail_autothread and thread_id:
|
||||||
|
message_ids = messages.search(cr, uid, ['&',('res_id', '=', thread_id),('model','=',model)], context=context)
|
||||||
|
if len(message_ids):
|
||||||
|
parent_id = min(message_ids)
|
||||||
|
|
||||||
|
|
||||||
values = kwargs
|
values = kwargs
|
||||||
values.update({
|
values.update({
|
||||||
'model': context.get('thread_model', self._name) if thread_id else False,
|
'model': model,
|
||||||
'res_id': thread_id or False,
|
'res_id': thread_id or False,
|
||||||
'body': body,
|
'body': body,
|
||||||
'subject': subject,
|
'subject': subject or False,
|
||||||
'type': type,
|
'type': type,
|
||||||
'parent_id': parent_id,
|
'parent_id': parent_id,
|
||||||
'attachment_ids': attachment_ids,
|
'attachment_ids': attachment_ids,
|
||||||
|
'subtype_id': subtype_id,
|
||||||
})
|
})
|
||||||
for x in ('from', 'to', 'cc'): values.pop(x, None) # Avoid warnings
|
# Avoid warnings about non-existing fields
|
||||||
return self.pool.get('mail.message').create(cr, uid, values, context=context)
|
for x in ('from', 'to', 'cc'):
|
||||||
|
values.pop(x, None)
|
||||||
|
|
||||||
|
return messages.create(cr, uid, values, context=context)
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Followers API
|
# Followers API
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
|
|
||||||
def message_subscribe_users(self, cr, uid, ids, user_ids=None, context=None):
|
def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification',
|
||||||
|
subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
|
||||||
|
added_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type,
|
||||||
|
subtype=subtype, parent_id=parent_id, attachments=attachments, context=context)
|
||||||
|
added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id])
|
||||||
|
|
||||||
|
return added_message
|
||||||
|
|
||||||
|
def get_message_subtypes(self, cr, uid, ids, context=None):
|
||||||
|
""" message_subtype_data: data about document subtypes: which are
|
||||||
|
available, which are followed if any """
|
||||||
|
return self._get_subscription_data(cr, uid, ids, None, None, context=context)
|
||||||
|
|
||||||
|
def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None):
|
||||||
""" Wrapper on message_subscribe, using users. If user_ids is not
|
""" Wrapper on message_subscribe, using users. If user_ids is not
|
||||||
provided, subscribe uid instead. """
|
provided, subscribe uid instead. """
|
||||||
if not user_ids: user_ids = [uid]
|
if not user_ids:
|
||||||
partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
|
user_ids = [uid]
|
||||||
return self.message_subscribe(cr, uid, ids, partner_ids, context=context)
|
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
|
||||||
|
return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context)
|
||||||
|
|
||||||
def message_subscribe(self, cr, uid, ids, partner_ids, context=None):
|
def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
|
||||||
""" Add partners to the records followers. """
|
""" Add partners to the records followers. """
|
||||||
return self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context)
|
self.write(cr, uid, ids, {'message_follower_ids': [(4, pid) for pid in partner_ids]}, context=context)
|
||||||
|
# if subtypes are not specified (and not set to a void list), fetch default ones
|
||||||
|
if subtype_ids is None:
|
||||||
|
subtype_obj = self.pool.get('mail.message.subtype')
|
||||||
|
subtype_ids = subtype_obj.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context)
|
||||||
|
# update the subscriptions
|
||||||
|
fol_obj = self.pool.get('mail.followers')
|
||||||
|
fol_ids = fol_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context)
|
||||||
|
fol_obj.write(cr, uid, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context)
|
||||||
|
return True
|
||||||
|
|
||||||
def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None):
|
def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None):
|
||||||
""" Wrapper on message_subscribe, using users. If user_ids is not
|
""" Wrapper on message_subscribe, using users. If user_ids is not
|
||||||
provided, unsubscribe uid instead. """
|
provided, unsubscribe uid instead. """
|
||||||
if not user_ids: user_ids = [uid]
|
if not user_ids:
|
||||||
partner_ids = [user['partner_id'][0] for user in self.pool.get('res.users').read(cr, uid, user_ids, ['partner_id'], context=context)]
|
user_ids = [uid]
|
||||||
|
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
|
||||||
return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
|
return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
|
||||||
|
|
||||||
def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None):
|
def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None):
|
||||||
|
@ -674,3 +762,5 @@ class mail_thread(osv.AbstractModel):
|
||||||
partner_id = %s
|
partner_id = %s
|
||||||
''', (ids, self._name, partner_id))
|
''', (ids, self._name, partner_id))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -12,16 +12,22 @@
|
||||||
<menuitem id="mail_feeds" name="Feeds" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
|
<menuitem id="mail_feeds" name="Feeds" parent="mail.mail_feeds_main" groups="base.group_user" sequence="10"/>
|
||||||
<menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/>
|
<menuitem id="mail_my_stuff" name="Organizer" parent="mail.mail_feeds_main"/>
|
||||||
|
|
||||||
<record id="mail_wallfeeds" model="ir.ui.menu">
|
<record id="mail_inboxfeeds" model="ir.ui.menu">
|
||||||
<field name="name">My Feeds</field>
|
<field name="name">Inbox</field>
|
||||||
<field name="sequence" eval="10"/>
|
<field name="sequence" eval="10"/>
|
||||||
<field name="action" ref="action_mail_all_feeds"/>
|
<field name="action" ref="action_mail_inbox_feeds"/>
|
||||||
<field name="parent_id" ref="mail_feeds"/>
|
<field name="parent_id" ref="mail_feeds"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="mail_myfeeds" model="ir.ui.menu">
|
<record id="mail_archivesfeeds" model="ir.ui.menu">
|
||||||
<field name="name">My Posts</field>
|
<field name="name">Archives</field>
|
||||||
<field name="sequence" eval="11"/>
|
<field name="sequence" eval="11"/>
|
||||||
<field name="action" ref="action_mail_my_feeds"/>
|
<field name="action" ref="action_mail_archives_feeds"/>
|
||||||
|
<field name="parent_id" ref="mail_feeds"/>
|
||||||
|
</record>
|
||||||
|
<record id="mail_sentfeeds" model="ir.ui.menu">
|
||||||
|
<field name="name">Sent</field>
|
||||||
|
<field name="sequence" eval="12"/>
|
||||||
|
<field name="action" ref="action_mail_sent_feeds"/>
|
||||||
<field name="parent_id" ref="mail_feeds"/>
|
<field name="parent_id" ref="mail_feeds"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class res_partner_mail(osv.Model):
|
||||||
""" Update partner to add a field about notification preferences """
|
""" Update partner to add a field about notification preferences """
|
||||||
_name = "res.partner"
|
_name = "res.partner"
|
||||||
_inherit = ['res.partner', 'mail.thread']
|
_inherit = ['res.partner', 'mail.thread']
|
||||||
|
_mail_autothread = False
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'notification_email_send': fields.selection([
|
'notification_email_send': fields.selection([
|
||||||
|
@ -41,5 +42,4 @@ class res_partner_mail(osv.Model):
|
||||||
'notification_email_send': lambda *args: 'comment'
|
'notification_email_send': lambda *args: 'comment'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//sheet" position="after">
|
<xpath expr="//sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"
|
<field name="message_ids" widget="mail_thread"
|
||||||
options='{"thread_level": 1}'/>
|
options='{"thread_level": 1}'/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
|
|
|
@ -11,4 +11,7 @@ access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
|
||||||
access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
|
access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
|
||||||
access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
|
access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
|
||||||
access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
|
access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
|
||||||
|
access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1
|
||||||
|
access_mail_message_subtype,mail.message.subtype,model_mail_message_subtype,,1,1,1,1
|
||||||
|
access_mail_mail_user,mail.mail,model_mail_mail,base.group_user,1,1,1,0
|
||||||
access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
|
access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
|
||||||
|
|
|
|
@ -14,7 +14,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* Wall
|
/* Wall
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -37,6 +36,21 @@
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* Followers
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
.openerp div.oe_mail_recthread_aside h4 {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.openerp div.oe_mail_recthread_aside button {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.openerp div.oe_mail_recthread_aside label,
|
||||||
|
.openerp div.oe_mail_recthread_aside input {
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Specific display of threads in the wall */
|
/* Specific display of threads in the wall */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
@ -50,22 +64,12 @@
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_subthread img {
|
.openerp div.oe_thread_placeholder img {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_msg_content {
|
.openerp div.oe_thread_placeholder div.oe_mail_msg_content {
|
||||||
position: relative;
|
|
||||||
width: 486px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openerp div.oe_mail_msg_content > li {
|
|
||||||
float: left;
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_subthread div.oe_mail_msg_content {
|
|
||||||
width: 440px;
|
width: 440px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +82,7 @@
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_recthread_main {
|
.openerp .oe_mail_record_wall > .oe_mail_wall_threads {
|
||||||
float: left;
|
float: left;
|
||||||
width: 560px;
|
width: 560px;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +100,7 @@
|
||||||
width: 120px;
|
width: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp button.oe_mail_button_mouseout {
|
.openerp .oe_mail_recthread_aside .oe_follower.oe_follow {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #8a89ba;
|
background-color: #8a89ba;
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#8a89ba), to(#807fb4));
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#8a89ba), to(#807fb4));
|
||||||
|
@ -106,9 +110,7 @@
|
||||||
background-image: -o-linear-gradient(top, #8a89ba, #807fb4);
|
background-image: -o-linear-gradient(top, #8a89ba, #807fb4);
|
||||||
background-image: linear-gradient(to bottom, #8a89ba, #807fb4);
|
background-image: linear-gradient(to bottom, #8a89ba, #807fb4);
|
||||||
}
|
}
|
||||||
|
.openerp .oe_mail_recthread_aside .oe_follower.oe_following {
|
||||||
.openerp button.oe_mail_button_mouseover {
|
|
||||||
display: none;
|
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #dc5f59;
|
background-color: #dc5f59;
|
||||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630));
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630));
|
||||||
|
@ -119,17 +121,38 @@
|
||||||
background-image: linear-gradient(to bottom, #dc5f59, #b33630);
|
background-image: linear-gradient(to bottom, #dc5f59, #b33630);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.openerp .oe_mail_recthread_aside .oe_follower span {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.openerp .oe_mail_recthread_aside .oe_following span.oe_following,
|
||||||
|
.openerp .oe_mail_recthread_aside .oe_notfollow span.oe_follow {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_recthread_followers {
|
.openerp div.oe_mail_recthread_followers {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* Followers
|
/* subtypes
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
||||||
.openerp div.oe_mail_recthread_aside h4 {
|
.openerp .oe_mouse_subtypes {
|
||||||
display: inline-block;
|
display:inline-block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
.openerp .oe_mouse_subtypes .oe_recthread_subtypes {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.openerp .oe_mouse_subtypes.oe_mouseout .oe_recthread_subtypes {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.openerp .oe_mouse_subtypes.oe_mouseover .oe_recthread_subtypes {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -140,6 +163,8 @@
|
||||||
display: none;
|
display: none;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
z-index:5;
|
||||||
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_action:after {
|
.openerp div.oe_mail_thread_action:after {
|
||||||
|
@ -168,15 +193,20 @@
|
||||||
-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
|
-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openerp .oe_mail_vote_count,
|
||||||
|
.openerp .oe_mail_msg_vote{
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_display {
|
.openerp div.oe_mail_thread_display {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_subthread {
|
.openerp div.oe_thread_placeholder {
|
||||||
margin-left: 66px;
|
margin-left: 66px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_subthread li.oe_mail_thread_msg:last-child {
|
.openerp div.oe_thread_placeholder li.oe_mail_thread_msg:last-child {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +221,15 @@
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openerp li.oe_mail_thread_msg.oe_mail_read,
|
||||||
|
.openerp li.oe_mail_thread_msg.oe_mail_read div {
|
||||||
|
background-color: #F0F0F0;
|
||||||
|
}
|
||||||
|
.openerp li.oe_mail_thread_msg.oe_mail_read li.oe_mail_thread_msg.oe_mail_unread,
|
||||||
|
.openerp li.oe_mail_thread_msg.oe_mail_read li.oe_mail_thread_msg.oe_mail_unread div {
|
||||||
|
background-color: #F6F6F6;
|
||||||
|
}
|
||||||
|
|
||||||
.openerp li.oe_mail_thread_msg > div:after {
|
.openerp li.oe_mail_thread_msg > div:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -202,18 +241,15 @@
|
||||||
margin: 0 0 4px 0;
|
margin: 0 0 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp .oe_mail_msg_notification,
|
.openerp .oe_mail_msg_notification,
|
||||||
.openerp .oe_mail_msg_comment,
|
.openerp .oe_mail_msg_expandable,
|
||||||
|
.openerp .oe_mail_msg_comment,
|
||||||
.openerp .oe_mail_msg_email {
|
.openerp .oe_mail_msg_email {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: white;
|
background: white;
|
||||||
border-top: 1px solid #ebebeb;
|
border-top: 1px solid #ebebeb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp div.oe_mail_thread_subthread .oe_mail_msg_comment {
|
|
||||||
background: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openerp .oe_mail_msg_notification:after,
|
.openerp .oe_mail_msg_notification:after,
|
||||||
.openerp .oe_mail_msg_comment:after,
|
.openerp .oe_mail_msg_comment:after,
|
||||||
.openerp .oe_mail_msg_email:after {
|
.openerp .oe_mail_msg_email:after {
|
||||||
|
@ -222,8 +258,15 @@
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp .oe_mail_msg_content {
|
.openerp div.oe_mail_msg_content {
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
width: 486px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openerp div.oe_mail_msg_content > li {
|
||||||
float: left;
|
float: left;
|
||||||
|
margin-right: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openerp .oe_mail_msg_content:after {
|
.openerp .oe_mail_msg_content:after {
|
||||||
|
@ -266,7 +309,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* mail.compose.message form view & OpenERP hacks
|
/* mail.compose.message form view & OpenERP hacks
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -371,15 +413,38 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dropdown menu */
|
/* Dropdown menu */
|
||||||
.openerp .oe_mail_msg_content .oe_dropdown_toggle {
|
/*.openerp .oe_mail_msg_content .oe_dropdown_toggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
right: 3px;
|
right: 3px;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
.openerp .oe_mail .oe_semantic_html_override {
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openerp .oe_mail ul.oe_header {
|
||||||
|
position: absolute;
|
||||||
|
right: 3px;
|
||||||
|
top: -6px;
|
||||||
|
display: none;
|
||||||
|
z-index: 10;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openerp .oe_mail ul.oe_header a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openerp .oe_mail .oe_semantic_html_override:hover > ul.oe_header {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openerp .oe_mail ul.oe_header>li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.openerp .oe_mail_msg_content .oe_dropdown_arrow:after {
|
.openerp .oe_mail_msg_content .oe_dropdown_arrow:after {
|
||||||
border-top: 4px solid transparent;
|
|
||||||
}
|
|
||||||
.openerp .oe_mail_msg_content:hover .oe_dropdown_arrow:after {
|
|
||||||
border-top: 4px solid #404040;
|
border-top: 4px solid #404040;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,7 +29,9 @@ openerp_mail_followers = function(session, mail) {
|
||||||
this.options.context = this.node.attrs.context;
|
this.options.context = this.node.attrs.context;
|
||||||
this.options.comment = this.node.attrs.help || false;
|
this.options.comment = this.node.attrs.help || false;
|
||||||
this.ds_model = new session.web.DataSetSearch(this, this.view.model);
|
this.ds_model = new session.web.DataSetSearch(this, this.view.model);
|
||||||
|
this.sub_model = new session.web.DataSetSearch(this,'mail.message.subtype');
|
||||||
this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
|
this.ds_follow = new session.web.DataSetSearch(this, this.field.relation);
|
||||||
|
this.follower_model = new session.web.DataSetSearch(this,'mail.followers');
|
||||||
},
|
},
|
||||||
|
|
||||||
start: function() {
|
start: function() {
|
||||||
|
@ -51,11 +53,33 @@ openerp_mail_followers = function(session, mail) {
|
||||||
|
|
||||||
bind_events: function() {
|
bind_events: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.$('button.oe_mail_button_unfollow').on('click', function () { self.do_unfollow(); })
|
this.$('div.oe_mouse_subtypes')
|
||||||
.mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
|
.on('mouseover', function () {
|
||||||
.mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
|
$(this).removeClass('oe_mouseout').addClass('oe_mouseover');
|
||||||
this.$el.on('click', 'button.oe_mail_button_follow', function () { self.do_follow(); });
|
self.display_subtypes();
|
||||||
this.$el.on('click', 'a.oe_mail_invite', function(event) {
|
})
|
||||||
|
.on('mouseleave', function () {
|
||||||
|
$(this).removeClass('oe_mouseover').addClass('oe_mouseout');
|
||||||
|
self.display_subtypes();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$('button.oe_follower')
|
||||||
|
.on('click', function () {
|
||||||
|
if($(this).hasClass('oe_notfollow'))
|
||||||
|
self.do_follow();
|
||||||
|
else
|
||||||
|
self.do_unfollow();
|
||||||
|
})
|
||||||
|
.on('mouseover', function () {
|
||||||
|
$(this).removeClass('oe_mouseout').addClass('oe_mouseover');
|
||||||
|
})
|
||||||
|
.on('mouseleave', function () {
|
||||||
|
$(this).removeClass('oe_mouseover').addClass('oe_mouseout');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$el.on('click', 'ul.oe_subtypes input', function () { self.do_update_subscription(); })
|
||||||
|
|
||||||
|
this.$el.on('click', 'button.oe_invite', function(event) {
|
||||||
action = {
|
action = {
|
||||||
type: 'ir.actions.act_window',
|
type: 'ir.actions.act_window',
|
||||||
res_model: 'mail.wizard.invite',
|
res_model: 'mail.wizard.invite',
|
||||||
|
@ -74,28 +98,35 @@ openerp_mail_followers = function(session, mail) {
|
||||||
|
|
||||||
read_value: function() {
|
read_value: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.ds_model.read_ids([this.view.datarecord.id], ['message_is_follower', 'message_follower_ids']).then(function (results) {
|
return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) {
|
||||||
self.set_value(results[0].message_follower_ids, results[0].message_is_follower);
|
self.set_value(results[0].message_follower_ids);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
set_value: function(value_, message_is_follower) {
|
set_value: function(value_) {
|
||||||
this.reinit();
|
this.reinit();
|
||||||
if (! this.view.datarecord.id ||
|
return this.fetch_followers(value_ || this.get_value());
|
||||||
session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
|
},
|
||||||
this.$('div.oe_mail_recthread_aside').hide();
|
|
||||||
return;
|
set_is_follower: function(value_) {
|
||||||
|
for(var i in value_){
|
||||||
|
if(value_[i]['user_ids'][0]==this.session.uid)
|
||||||
|
this.message_is_follower=true;
|
||||||
|
this.display_buttons();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return this.fetch_followers(value_ || this.get_value(), message_is_follower);
|
this.message_is_follower=false;
|
||||||
|
this.display_buttons();
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
fetch_followers: function (value_, message_is_follower) {
|
fetch_followers: function (value_) {
|
||||||
this.value = value_;
|
this.value = value_ || {};
|
||||||
this.message_is_follower = message_is_follower || (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
|
this.message_is_follower = (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
|
||||||
return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic'));
|
if(value_)
|
||||||
|
return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/* Display generic info about follower, for people not having access to res_partner */
|
/* Display generic info about follower, for people not having access to res_partner */
|
||||||
display_generic: function (error, event) {
|
display_generic: function (error, event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -117,32 +148,88 @@ openerp_mail_followers = function(session, mail) {
|
||||||
display_followers: function (records) {
|
display_followers: function (records) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var node_user_list = this.$('ul.oe_mail_followers_display').empty();
|
var node_user_list = this.$('ul.oe_mail_followers_display').empty();
|
||||||
this.$('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + records.length + ')');
|
this.$('div.oe_mail_recthread_followers h4').html(this.options.title + (records.length>=5 ? ' (' + records.length + ')' : '') );
|
||||||
_(records).each(function (record) {
|
console.log(records);
|
||||||
|
for(var i=0; i<records.length&&i<5; i++) {
|
||||||
|
var record=records[i];
|
||||||
record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
|
record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
|
||||||
$(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
|
$(session.web.qweb.render('mail.followers.partner', {'record': record})).appendTo(node_user_list);
|
||||||
});
|
}
|
||||||
this.display_buttons();
|
self.set_is_follower(records);
|
||||||
},
|
},
|
||||||
|
|
||||||
display_buttons: function () {
|
display_buttons: function () {
|
||||||
this.$('button.oe_mail_button_follow').hide();
|
if (this.message_is_follower) {
|
||||||
this.$('button.oe_mail_button_unfollow').hide();
|
this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
|
||||||
this.$('span.oe_mail_invite_wrapper').hide();
|
}
|
||||||
if (! this.view.is_action_enabled('edit')) return;
|
else {
|
||||||
this.$('span.oe_mail_invite_wrapper').show();
|
this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
|
||||||
if (this.message_is_follower) { this.$('button.oe_mail_button_unfollow').show(); }
|
}
|
||||||
else if (this.message_is_follower == false) { this.$('button.oe_mail_button_follow').show(); }
|
|
||||||
|
if (this.view.is_action_enabled('edit'))
|
||||||
|
this.$('span.oe_mail_invite_wrapper').hide();
|
||||||
|
else
|
||||||
|
this.$('span.oe_mail_invite_wrapper').show();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
set_subtypes:function(data){
|
||||||
|
var self = this;
|
||||||
|
var records = data[this.view.datarecord.id].message_subtype_data;
|
||||||
|
_(records).each(function (record, record_name) {
|
||||||
|
record.name = record_name;
|
||||||
|
record.followed = record.followed || undefined;
|
||||||
|
$(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo( self.$('ul.oe_subtypes') );
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Display subtypes: {'name': default, followed} */
|
||||||
|
display_subtypes: function (visible) {
|
||||||
|
var self = this;
|
||||||
|
var recthread_subtypes = self.$('.oe_recthread_subtypes');
|
||||||
|
subtype_list_ul = self.$('ul.oe_subtypes');
|
||||||
|
|
||||||
|
if(subtype_list_ul.is(":empty")) {
|
||||||
|
var context = new session.web.CompoundContext(this.build_context(), {});
|
||||||
|
this.ds_model.call('get_message_subtypes',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
do_follow: function () {
|
do_follow: function () {
|
||||||
|
var self =this;
|
||||||
|
_(this.$('.oe_msg_subtype_check')).each(function(record){
|
||||||
|
$(record).attr('checked','checked');
|
||||||
|
});
|
||||||
var context = new session.web.CompoundContext(this.build_context(), {});
|
var context = new session.web.CompoundContext(this.build_context(), {});
|
||||||
return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value'));
|
return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], undefined, undefined, context]).pipe(function(value_){
|
||||||
|
self.read_value(value_);
|
||||||
|
if(!self.$('.oe_recthread_subtypes').is(":visible"))
|
||||||
|
self.display_subtypes(true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
do_unfollow: function () {
|
do_unfollow: function () {
|
||||||
|
_(this.$('.oe_msg_subtype_check')).each(function(record){
|
||||||
|
$(record).attr('checked',false);
|
||||||
|
});
|
||||||
var context = new session.web.CompoundContext(this.build_context(), {});
|
var context = new session.web.CompoundContext(this.build_context(), {});
|
||||||
return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value'));
|
return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
do_update_subscription: function () {
|
||||||
|
var context = new session.web.CompoundContext(this.build_context(), {});
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var checklist = new Array();
|
||||||
|
_(this.$('.oe_msg_subtype_check')).each(function(record){
|
||||||
|
if($(record).is(':checked')) {
|
||||||
|
checklist.push(parseInt($(record).data('id')))}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!checklist.length)
|
||||||
|
return this.do_unfollow();
|
||||||
|
else
|
||||||
|
return this.ds_model.call('message_subscribe_users',[[self.view.datarecord.id], undefined, checklist, context]).pipe(this.proxy('read_value'));
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
};
|
};
|
|
@ -47,11 +47,11 @@
|
||||||
Template used to display the communication history in documents
|
Template used to display the communication history in documents
|
||||||
form view.
|
form view.
|
||||||
-->
|
-->
|
||||||
<div t-name="mail.record_thread">
|
<div t-name="mail.record_thread" class="oe_mail_record_wall">
|
||||||
<!-- <h4>History and Comments</h4> -->
|
<!-- <h4>History and Comments</h4> -->
|
||||||
<div class="oe_mail_recthread_main">
|
<ul class="oe_mail_wall_threads">
|
||||||
<!-- contains the document thread -->
|
<!-- contains the document thread -->
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -62,12 +62,12 @@
|
||||||
for main thread composition form in document form view.
|
for main thread composition form in document form view.
|
||||||
-->
|
-->
|
||||||
<t t-name="mail.compose_message">
|
<t t-name="mail.compose_message">
|
||||||
<div>
|
<div class="oe_mail_compose_textarea">
|
||||||
<img class="oe_mail_icon oe_mail_frame oe_left" alt="User img"/>
|
<img class="oe_mail_icon oe_mail_frame oe_left" alt="User img"/>
|
||||||
<div class="oe_mail_msg_content">
|
<div class="oe_mail_msg_content">
|
||||||
<!-- contains the composition form -->
|
<!-- contains the composition form -->
|
||||||
<!-- default content: old basic textarea -->
|
<!-- default content: old basic textarea -->
|
||||||
<textarea class="oe_mail_compose_textarea" placeholder="Add your comment here..." onfocus="this.value = '';"/>
|
<textarea placeholder="Add your comment here..."/>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_clear"/>
|
<div class="oe_clear"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,72 +93,90 @@
|
||||||
container, holding the composition form. Then come the various
|
container, holding the composition form. Then come the various
|
||||||
messages. Then comes the 'more' button.
|
messages. Then comes the 'more' button.
|
||||||
-->
|
-->
|
||||||
<ul t-name="mail.thread" class="oe_mail oe_mail_thread oe_semantic_html_override">
|
<div t-name="mail.thread" class="oe_mail oe_mail_thread oe_semantic_html_override">
|
||||||
<div class="oe_mail_thread_action">
|
<div class="oe_mail_thread_action">
|
||||||
<!-- contains the composition box (form + image) -->
|
<!-- contains the composition box (form + image) -->
|
||||||
<t t-call="mail.compose_message"/>
|
<t t-call="mail.compose_message"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_mail_thread_display">
|
<ul class="oe_mail_thread_display">
|
||||||
<!-- contains the threads -->
|
<!-- contains the threads -->
|
||||||
</div>
|
</ul>
|
||||||
<div class="oe_mail_thread_more">
|
</div>
|
||||||
<button class="oe_mail_button_more" type="button">Load more messages</button>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- default layout -->
|
<!-- default layout -->
|
||||||
<li t-name="mail.thread.message" class="oe_mail oe_mail_thread_msg">
|
<li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.unread?'oe_mail_unread':'oe_mail_read'}" t-attf-data-msg_id="{widget.id}">
|
||||||
<div t-attf-class="oe_mail_msg_#{record.type} oe_semantic_html_override">
|
<div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
|
||||||
<img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="record.avatar"/>
|
<!-- message actions (read/unread, reply, delete...) -->
|
||||||
|
<ul class="oe_header">
|
||||||
|
<li class="placeholder-mail-vote"><t t-call="mail.thread.message.vote"/></li>
|
||||||
|
<li t-if="!widget.options.thread.display_on_flat and widget.unread" title="Read"><a class="oe_read oe_e">W</a></li>
|
||||||
|
<li t-if="!widget.options.thread.display_on_flat and !widget.unread" title="Set back to unread"><a class="oe_unread oe_e">h</a></li>
|
||||||
|
<li t-if="!widget.options.message.show_reply_by_email" title="Reply"><a class="oe_reply oe_e">)</a></li>
|
||||||
|
<li t-if="widget.options.message.show_reply_by_email"><a class="oe_reply_by_email oe_e" title="Reply by mail">)</a></li>
|
||||||
|
<t t-if="(widget.options.message.show_reply || widget.options.message.show_reply_by_email || (widget.is_author and widget.options.message.show_dd_delete) || widget.type == 'email')">
|
||||||
|
<li>
|
||||||
|
<span class="oe_dropdown_toggle">
|
||||||
|
<a class="oe_e" title="More options">í</a>
|
||||||
|
<ul class="oe_dropdown_menu">
|
||||||
|
<li t-if="widget.is_author and widget.options.message.show_dd_delete"><a class="oe_mail_msg_delete">Delete</a></li>
|
||||||
|
<!-- Uncomment when adding subtype hiding
|
||||||
|
<li t-if="display['show_hide']">
|
||||||
|
<a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{widget.subtype}'>Hide '<t t-esc="widget.subtype"/>' for this document</a>
|
||||||
|
</li> -->
|
||||||
|
<li t-if="widget.options.message.show_reply" title="Reply"><a class="oe_reply oe_full_reply">Full reply</a></li>
|
||||||
|
<li t-if="widget.options.message.show_reply_by_email"><a class="oe_reply_by_email oe_full_reply" title="Reply by mail">Full reply</a></li>
|
||||||
|
<li t-if="widget.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&id=#{widget.id}" >Details</a></li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a t-attf-href="#model=res.partner&id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
|
||||||
|
<img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="widget.avatar"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="oe_mail_msg_content">
|
<div class="oe_mail_msg_content">
|
||||||
<!-- dropdown menu with message options and actions -->
|
|
||||||
<span class="oe_dropdown_toggle oe_dropdown_arrow">
|
|
||||||
<ul class="oe_dropdown_menu">
|
|
||||||
<li t-if="record.is_author and options.show_dd_delete"><a class="oe_mail_msg_delete" t-attf-data-id='{record.id}'>Delete</a></li>
|
|
||||||
<li t-if="options.show_dd_hide"><a class="oe_mail_msg_hide" t-attf-data-id='{record.id}'>Remove notification</a></li>
|
|
||||||
<!-- Uncomment when adding subtype hiding
|
|
||||||
<li t-if="display['show_hide']">
|
|
||||||
<a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{record.subtype}'>Hide '<t t-esc="record.subtype"/>' for this document</a>
|
|
||||||
</li> -->
|
|
||||||
<li t-if="options.show_dd_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Quote and reply</a></li>
|
|
||||||
<li t-if="record.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&id=#{record.id}" >Details</a></li>
|
|
||||||
</ul>
|
|
||||||
</span>
|
|
||||||
<!-- message itself -->
|
<!-- message itself -->
|
||||||
<div class="oe_mail_msg">
|
<div class="oe_mail_msg">
|
||||||
<h1 t-if="record.subject" class="oe_mail_msg_title">
|
<h1 t-if="widget.subject" class="oe_mail_msg_title">
|
||||||
<t t-raw="record.subject"/>
|
<t t-raw="widget.subject"/>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="oe_mail_msg_body">
|
|
||||||
<t t-if="options.show_record_name and record.record_name and (!record.subject) and (options.thread_level > 0)">
|
|
||||||
<a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a>
|
|
||||||
</t>
|
|
||||||
<t t-raw="record.body"/>
|
|
||||||
</div>
|
|
||||||
<div class="oe_clear"/>
|
|
||||||
<ul class="oe_mail_msg_footer">
|
<ul class="oe_mail_msg_footer">
|
||||||
<li t-if="options.show_record_name and record.record_name and record.subject and options.thread_level > 0">
|
<li t-if="widget.author_id"><a t-attf-href="#model=res.partner&id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a></li>
|
||||||
<a t-attf-href="#model=#{record.model}&id=#{record.res_id}"><t t-raw="record.record_name"/></a>
|
<li><span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span></li>
|
||||||
</li>
|
|
||||||
<li t-if="record.author_id"><a t-attf-href="#model=res.partner&id=#{record.author_id[0]}"><t t-raw="record.author_id[1]"/></a></li>
|
<li t-if="widget.attachment_ids.length > 0">
|
||||||
<li><span t-att-title="record.date"><t t-raw="record.timerelative"/></span></li>
|
|
||||||
<t t-call="mail.thread.message.vote"/>
|
|
||||||
<li t-if="options.show_reply"><a class="oe_mail_msg_reply">Reply</a></li>
|
|
||||||
<li t-if="options.show_reply_by_email"><a class="oe_mail_msg_reply_by_email" t-attf-data-msg_id="{record.id}">Reply</a></li>
|
|
||||||
<li t-if="record.attachment_ids.length > 0">
|
|
||||||
<a class="oe_mail_msg_view_attachments">
|
<a class="oe_mail_msg_view_attachments">
|
||||||
<t t-if="record.attachment_ids.length == 1">1 Attachment</t>
|
<t t-if="widget.attachment_ids.length == 1">1 Attachment</t>
|
||||||
<t t-if="record.attachment_ids.length > 1"><t t-raw="record.attachment_ids.length"/> Attachments</t>
|
<t t-if="widget.attachment_ids.length > 1"><t t-raw="widget.attachment_ids.length"/> Attachments</t>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<t t-if="record.attachment_ids.length > 0">
|
<div class="oe_clear"/>
|
||||||
|
<div class="oe_mail_msg_body">
|
||||||
|
<t t-if="widget.options.message.show_record_name and widget.record_name and (!widget.subject) and widget.options.thread._parents.length<=widget.options.thread.thread_level and widget.model!='res.partner'">
|
||||||
|
<a class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&id=#{widget.res_id}"><t t-raw="widget.record_name"/></a>
|
||||||
|
</t>
|
||||||
|
<t t-raw="widget.body"/>
|
||||||
|
</div>
|
||||||
|
<t t-if="widget.attachment_ids.length > 0">
|
||||||
<div class="oe_clear"></div>
|
<div class="oe_clear"></div>
|
||||||
<t t-call="mail.thread.message.attachments"/>
|
<t t-call="mail.thread.message.attachments"/>
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="oe_thread_placeholder"></div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- expandable message layout -->
|
||||||
|
<li t-name="mail.thread.expandable" t-attf-class="oe_mail oe_mail_thread_msg oe_mail_unread" t-attf-data-thread_id="{widget.id}">
|
||||||
|
<div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
|
||||||
|
<div class="oe_mail_msg_content oe_mail_msg_more_message">
|
||||||
|
<a class="oe_mail_fetch_more">Load more messages <span t-if="widget.nb_messages>0">(<t t-raw="widget.nb_messages"/> messages not display)</span>...</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -181,14 +199,25 @@
|
||||||
<!-- mail.thread.message.vote
|
<!-- mail.thread.message.vote
|
||||||
Template used to display Like/Unlike in a mail.message
|
Template used to display Like/Unlike in a mail.message
|
||||||
-->
|
-->
|
||||||
<li t-name="mail.thread.message.vote">
|
<span t-name="mail.thread.message.vote">
|
||||||
<t t-if='record.vote_user_ids.length > 0'>
|
<span class="oe_left oe_mail_vote_count">
|
||||||
<span class="oe_left oe_mail_vote_count"><t t-esc="record.vote_user_ids.length"/> votes</span>
|
<t t-if='widget.has_voted'>
|
||||||
</t>
|
You
|
||||||
<button t-attf-class="oe_mail_msg_vote oe_tag" t-attf-data-msg_id="{record.id}">
|
</t>
|
||||||
<t t-if="! record.has_voted"><span>+1</span></t>
|
<t t-if='(widget.vote_user_ids.length-(widget.has_voted?1:0)) > 0'>
|
||||||
<t t-if="record.has_voted"><span>-1</span></t>
|
<t t-if='widget.has_voted'> and </t>
|
||||||
|
<t t-esc="widget.vote_user_ids.length"/> people
|
||||||
|
</t>
|
||||||
|
<t t-if='widget.vote_user_ids.length > 0'>
|
||||||
|
agree
|
||||||
|
</t>
|
||||||
|
</span>
|
||||||
|
<button t-attf-class="oe_mail_msg_vote oe_tag">
|
||||||
|
<span>
|
||||||
|
<t t-if="!widget.has_voted">Agree</t>
|
||||||
|
<t t-if="widget.has_voted">Unagree</t>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</span>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,12 +3,20 @@
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
followers main template
|
followers main template
|
||||||
Template used to display the followers and the actions in a record.
|
Template used to display the followers, the actions and the subtypes in a record.
|
||||||
-->
|
-->
|
||||||
<div t-name="mail.followers" class="oe_mail_recthread_aside oe_semantic_html_override">
|
<div t-name="mail.followers" class="oe_mail_recthread_aside oe_semantic_html_override">
|
||||||
<div class="oe_mail_recthread_actions">
|
<div class="oe_mail_recthread_actions">
|
||||||
<button type="button" class="oe_mail_button_follow">Follow</button>
|
<div class="oe_mouse_subtypes">
|
||||||
<button type="button" class="oe_mail_button_unfollow oe_mail_button_mouseout">Following</button>
|
<button type="button" class="oe_follower oe_notfollow">
|
||||||
|
<span class="oe_follow">Follow</span>
|
||||||
|
<span class="oe_unfollow">Unfollow</span>
|
||||||
|
<span class="oe_following">Following</span>
|
||||||
|
</button>
|
||||||
|
<div class="oe_recthread_subtypes">
|
||||||
|
<ul class="oe_subtypes"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_grey">
|
<div class="oe_grey">
|
||||||
<t t-if="widget.options.comment">
|
<t t-if="widget.options.comment">
|
||||||
|
@ -16,8 +24,9 @@
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_mail_recthread_followers">
|
<div class="oe_mail_recthread_followers">
|
||||||
|
<button type="button" class="oe_invite"><span>Invite</span></button>
|
||||||
<t t-if="widget.options.title">
|
<t t-if="widget.options.title">
|
||||||
<h4><t t-raw="widget.options.title"/></h4><span class="oe_mail_invite_wrapper"> · <a class="oe_mail_invite" >Invite partners</a></span>
|
<h4><t t-raw="widget.options.title"/></h4>
|
||||||
</t>
|
</t>
|
||||||
<ul class="oe_mail_followers_display"></ul>
|
<ul class="oe_mail_followers_display"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,6 +39,19 @@
|
||||||
<li t-name="mail.followers.partner">
|
<li t-name="mail.followers.partner">
|
||||||
<img class="oe_mail_thumbnail oe_mail_frame" t-attf-src="{record.avatar_url}"/>
|
<img class="oe_mail_thumbnail oe_mail_frame" t-attf-src="{record.avatar_url}"/>
|
||||||
<a t-attf-href="#model=res.partner&id=#{record.id}"><t t-raw="record.name"/></a>
|
<a t-attf-href="#model=res.partner&id=#{record.id}"><t t-raw="record.name"/></a>
|
||||||
|
</li>\
|
||||||
|
|
||||||
|
<!--
|
||||||
|
followers.subtype template
|
||||||
|
Template used to display message subtypes of a follower subscription
|
||||||
|
-->
|
||||||
|
<li t-name="mail.followers.subtype">
|
||||||
|
<table width="50%">
|
||||||
|
<tr>
|
||||||
|
<td><label t-att-for="'input_mail_followers_subtype_'+record.id"><t t-raw="record.name"/></label></td>
|
||||||
|
<td width="10%"><input type="checkbox" t-att-checked="record.followed" t-att-id="'input_mail_followers_subtype_'+record.id" t-att-data-id="record.id" t-att-name="record.name" class="oe_msg_subtype_check"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -131,9 +131,12 @@ class test_mail(TestMailMockups):
|
||||||
self.mail_message = self.registry('mail.message')
|
self.mail_message = self.registry('mail.message')
|
||||||
self.mail_notification = self.registry('mail.notification')
|
self.mail_notification = self.registry('mail.notification')
|
||||||
self.mail_followers = self.registry('mail.followers')
|
self.mail_followers = self.registry('mail.followers')
|
||||||
|
self.mail_message_subtype = self.registry('mail.message.subtype')
|
||||||
self.res_users = self.registry('res.users')
|
self.res_users = self.registry('res.users')
|
||||||
self.res_partner = self.registry('res.partner')
|
self.res_partner = self.registry('res.partner')
|
||||||
|
|
||||||
|
self.user_demo = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, 'base', 'user_demo')[1]
|
||||||
|
|
||||||
# Mock send_get_mail_body to test its functionality without other addons override
|
# Mock send_get_mail_body to test its functionality without other addons override
|
||||||
self._send_get_mail_body = self.registry('mail.mail').send_get_mail_body
|
self._send_get_mail_body = self.registry('mail.mail').send_get_mail_body
|
||||||
self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body
|
self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body
|
||||||
|
@ -252,30 +255,64 @@ class test_mail(TestMailMockups):
|
||||||
follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
|
follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
|
||||||
self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data')
|
self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data')
|
||||||
|
|
||||||
def test_11_message_followers(self):
|
def test_11_message_followers_and_subtypes(self):
|
||||||
""" Tests designed for the subscriber API. """
|
""" Tests designed for the subscriber API as well as message subtypes """
|
||||||
cr, uid = self.cr, self.uid
|
cr, uid = self.cr, self.uid
|
||||||
user_admin = self.res_users.browse(cr, uid, uid)
|
user_admin = self.res_users.browse(cr, uid, uid)
|
||||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||||
|
# Data: user Raoul
|
||||||
# Create user Raoul
|
|
||||||
user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul'})
|
user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul'})
|
||||||
user_raoul = self.res_users.browse(cr, uid, user_raoul_id)
|
user_raoul = self.res_users.browse(cr, uid, user_raoul_id)
|
||||||
|
# Data: message subtypes
|
||||||
|
self.mail_message_subtype.create(cr, uid, {'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.group'})
|
||||||
|
self.mail_message_subtype.create(cr, uid, {'name': 'mt_other_def', 'default': True, 'res_model': 'crm.lead'})
|
||||||
|
self.mail_message_subtype.create(cr, uid, {'name': 'mt_all_def', 'default': True, 'res_model': False})
|
||||||
|
mt_mg_nodef = self.mail_message_subtype.create(cr, uid, {'name': 'mt_mg_nodef', 'default': False, 'res_model': 'mail.group'})
|
||||||
|
mt_all_nodef = self.mail_message_subtype.create(cr, uid, {'name': 'mt_all_nodef', 'default': False, 'res_model': False})
|
||||||
|
default_group_subtypes = self.mail_message_subtype.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', 'mail.group'), ('res_model', '=', False)])
|
||||||
|
|
||||||
# Subscribe Raoul three times (niak niak) through message_subscribe_users
|
# ----------------------------------------
|
||||||
|
# CASE1: test subscriptions with subtypes
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
# Do: Subscribe Raoul three times (niak niak) through message_subscribe_users
|
||||||
group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id])
|
group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id])
|
||||||
group_pigs.message_subscribe_users([user_raoul_id])
|
group_pigs.message_subscribe_users([user_raoul_id])
|
||||||
group_pigs.refresh()
|
group_pigs.refresh()
|
||||||
|
# Test: 2 followers (Admin and Raoul)
|
||||||
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
|
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
|
||||||
self.assertEqual(len(follower_ids), 2, 'There should be 2 Pigs fans')
|
self.assertEqual(len(follower_ids), 2, 'There should be 2 Pigs fans')
|
||||||
self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), 'Admin and Raoul should be the only 2 Pigs fans')
|
self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), 'Admin and Raoul should be the only 2 Pigs fans')
|
||||||
|
# Test: Raoul follows default subtypes
|
||||||
|
fol_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id), ('partner_id', '=', user_raoul.partner_id.id)])
|
||||||
|
fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0]
|
||||||
|
fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids])
|
||||||
|
self.assertEqual(set(fol_subtype_ids), set(default_group_subtypes), 'subscription subtypes are incorrect')
|
||||||
|
|
||||||
# Unsubscribe Raoul twice through message_unsubscribe_users
|
# Do: Unsubscribe Raoul twice through message_unsubscribe_users
|
||||||
group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id])
|
group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id])
|
||||||
group_pigs.refresh()
|
group_pigs.refresh()
|
||||||
|
# Test: 1 follower (Admin)
|
||||||
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
|
follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
|
||||||
self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan')
|
self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan')
|
||||||
|
|
||||||
|
# Do: subscribe Admin with subtype_ids
|
||||||
|
group_pigs.message_subscribe_users([uid], [mt_mg_nodef, mt_all_nodef])
|
||||||
|
fol_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id), ('partner_id', '=', user_admin.partner_id.id)])
|
||||||
|
fol_obj = self.mail_followers.browse(cr, uid, fol_ids)[0]
|
||||||
|
fol_subtype_ids = set([subtype.id for subtype in fol_obj.subtype_ids])
|
||||||
|
self.assertEqual(set(fol_subtype_ids), set([mt_mg_nodef, mt_all_nodef]), 'subscription subtypes are incorrect')
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# CASE2: test mail_thread fields
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
|
group_pigs.refresh()
|
||||||
|
self.assertEqual(set(group_pigs.message_subtype_data.keys()), set(['comment', 'mt_mg_def', 'mt_all_def', 'mt_mg_nodef', 'mt_all_nodef']), 'mail.group available subtypes incorrect')
|
||||||
|
self.assertFalse(group_pigs.message_subtype_data['comment']['followed'], 'Admin should not follow comments in pigs')
|
||||||
|
self.assertTrue(group_pigs.message_subtype_data['mt_mg_nodef']['followed'], 'Admin should follow mt_mg_nodef in pigs')
|
||||||
|
self.assertTrue(group_pigs.message_subtype_data['mt_all_nodef']['followed'], 'Admin should follow mt_all_nodef in pigs')
|
||||||
|
|
||||||
def test_20_message_post(self):
|
def test_20_message_post(self):
|
||||||
""" Tests designed for message_post. """
|
""" Tests designed for message_post. """
|
||||||
cr, uid = self.cr, self.uid
|
cr, uid = self.cr, self.uid
|
||||||
|
@ -283,8 +320,6 @@ class test_mail(TestMailMockups):
|
||||||
user_admin = self.res_users.browse(cr, uid, uid)
|
user_admin = self.res_users.browse(cr, uid, uid)
|
||||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||||
|
|
||||||
# 0 - Admin
|
|
||||||
p_a_id = user_admin.partner_id.id
|
|
||||||
# 1 - Bert Tartopoils, with email, should receive emails for comments and emails
|
# 1 - Bert Tartopoils, with email, should receive emails for comments and emails
|
||||||
p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
|
p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
|
||||||
# 2 - Carine Poilvache, with email, should never receive emails
|
# 2 - Carine Poilvache, with email, should never receive emails
|
||||||
|
@ -306,9 +341,12 @@ class test_mail(TestMailMockups):
|
||||||
_mail_bodyalt2 = 'Pigs rules\nAdmin'
|
_mail_bodyalt2 = 'Pigs rules\nAdmin'
|
||||||
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
|
_attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
# CASE1: post comment, body and subject specified
|
# CASE1: post comment, body and subject specified
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
self._init_mock_build_email()
|
self._init_mock_build_email()
|
||||||
msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, type='comment')
|
msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, type='comment', subtype='mt_comment')
|
||||||
message = self.mail_message.browse(cr, uid, msg_id)
|
message = self.mail_message.browse(cr, uid, msg_id)
|
||||||
sent_emails = self._build_email_kwargs_list
|
sent_emails = self._build_email_kwargs_list
|
||||||
# Test: notifications have been deleted
|
# Test: notifications have been deleted
|
||||||
|
@ -325,7 +363,7 @@ class test_mail(TestMailMockups):
|
||||||
self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
|
self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
|
||||||
# Test: mail_message: partner_ids = group followers
|
# Test: mail_message: partner_ids = group followers
|
||||||
message_pids = set([partner.id for partner in message.partner_ids])
|
message_pids = set([partner.id for partner in message.partner_ids])
|
||||||
test_pids = set([p_a_id, p_b_id, p_c_id])
|
test_pids = set([p_b_id, p_c_id])
|
||||||
self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
|
self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
|
||||||
# Test: notification linked to this message = group followers = partner_ids
|
# Test: notification linked to this message = group followers = partner_ids
|
||||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
||||||
|
@ -335,10 +373,13 @@ class test_mail(TestMailMockups):
|
||||||
for sent_email in sent_emails:
|
for sent_email in sent_emails:
|
||||||
self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
|
self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
# CASE2: post an email with attachments, parent_id, partner_ids
|
# CASE2: post an email with attachments, parent_id, partner_ids
|
||||||
|
# ----------------------------------------
|
||||||
|
|
||||||
# TESTS: automatic subject, signature in body_html, attachments propagation
|
# TESTS: automatic subject, signature in body_html, attachments propagation
|
||||||
self._init_mock_build_email()
|
self._init_mock_build_email()
|
||||||
msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, type='email',
|
msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, type='email', subtype='mt_comment',
|
||||||
partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments)
|
partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments)
|
||||||
message = self.mail_message.browse(cr, uid, msg_id2)
|
message = self.mail_message.browse(cr, uid, msg_id2)
|
||||||
sent_emails = self._build_email_kwargs_list
|
sent_emails = self._build_email_kwargs_list
|
||||||
|
@ -356,7 +397,7 @@ class test_mail(TestMailMockups):
|
||||||
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
|
self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
|
||||||
# Test: mail_message: partner_ids = group followers
|
# Test: mail_message: partner_ids = group followers
|
||||||
message_pids = set([partner.id for partner in message.partner_ids])
|
message_pids = set([partner.id for partner in message.partner_ids])
|
||||||
test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id])
|
test_pids = set([p_b_id, p_c_id, p_d_id])
|
||||||
self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
|
self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
|
||||||
# Test: notifications linked to this message = group followers = partner_ids
|
# Test: notifications linked to this message = group followers = partner_ids
|
||||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
||||||
|
@ -394,8 +435,6 @@ class test_mail(TestMailMockups):
|
||||||
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
|
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
|
||||||
|
|
||||||
# Create partners
|
# Create partners
|
||||||
# 0 - Admin
|
|
||||||
p_a_id = user_admin.partner_id.id
|
|
||||||
# 1 - Bert Tartopoils, with email, should receive emails for comments and emails
|
# 1 - Bert Tartopoils, with email, should receive emails for comments and emails
|
||||||
p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
|
p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
|
||||||
# 2 - Carine Poilvache, with email, should never receive emails
|
# 2 - Carine Poilvache, with email, should never receive emails
|
||||||
|
@ -429,9 +468,10 @@ class test_mail(TestMailMockups):
|
||||||
self.assertEqual(message.body, _msg_body, 'mail.message incorrect body')
|
self.assertEqual(message.body, _msg_body, 'mail.message incorrect body')
|
||||||
# Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
|
# Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
|
||||||
msg_pids = [partner.id for partner in message.partner_ids]
|
msg_pids = [partner.id for partner in message.partner_ids]
|
||||||
test_pids = [p_a_id, p_b_id, p_c_id, p_d_id]
|
test_pids = [p_b_id, p_c_id, p_d_id]
|
||||||
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
|
||||||
self.assertEqual(len(notif_ids), 4, 'mail.message: too much notifications created')
|
|
||||||
|
self.assertEqual(len(notif_ids), 3, 'mail.message: too much notifications created')
|
||||||
self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect')
|
self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect')
|
||||||
|
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
@ -449,22 +489,15 @@ class test_mail(TestMailMockups):
|
||||||
self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
|
self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
|
||||||
self.assertEqual(compose.parent_id.id, message.id, 'mail.compose.message incorrect parent_id')
|
self.assertEqual(compose.parent_id.id, message.id, 'mail.compose.message incorrect parent_id')
|
||||||
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message incorrect content_subtype')
|
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message incorrect content_subtype')
|
||||||
|
|
||||||
# 2. Post the comment, get created message
|
|
||||||
parent_id = message.id
|
|
||||||
mail_compose.send_mail(cr, uid, [compose_id])
|
|
||||||
group_pigs.refresh()
|
|
||||||
message = group_pigs.message_ids[0]
|
|
||||||
# Test: mail.message: subject as Re:.., body in html, parent_id
|
# Test: mail.message: subject as Re:.., body in html, parent_id
|
||||||
self.assertEqual(message.subject, _msg_reply, 'mail.message incorrect subject')
|
self.assertEqual(compose.subject, _msg_reply, 'mail.message incorrect subject')
|
||||||
self.assertIn('Administrator wrote:<blockquote><pre>Pigs rules</pre></blockquote></div>', message.body, 'mail.message body is incorrect')
|
self.assertIn('Administrator wrote:<blockquote><pre>Pigs rules</pre></blockquote>', compose.body, 'mail.message body is incorrect')
|
||||||
self.assertEqual(message.parent_id and message.parent_id.id, parent_id, 'mail.message parent_id incorrect')
|
self.assertEqual(compose.parent_id and compose.parent_id.id, message.id, 'mail.message parent_id incorrect')
|
||||||
# Test: mail.message: attachments
|
# Test: mail.message: attachments
|
||||||
for attach in message.attachment_ids:
|
for attach in compose.attachment_ids:
|
||||||
self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
|
self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
|
||||||
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
|
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
|
||||||
self.assertIn((attach.name, attach.datas.decode('base64')), _attachments_test,
|
self.assertIn((attach.datas_fname, attach.datas.decode('base64')), _attachments_test, 'mail.message attachment name / data incorrect')
|
||||||
'mail.message attachment name / data incorrect')
|
|
||||||
|
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
# CASE3: mass_mail on Pigs and Bird
|
# CASE3: mass_mail on Pigs and Bird
|
||||||
|
@ -472,8 +505,8 @@ class test_mail(TestMailMockups):
|
||||||
|
|
||||||
# 1. mass_mail on pigs and bird
|
# 1. mass_mail on pigs and bird
|
||||||
compose_id = mail_compose.create(cr, uid,
|
compose_id = mail_compose.create(cr, uid,
|
||||||
{'subject': _subject, 'body': '${object.description}'},
|
{'subject': _subject, 'body': '${object.description}', 'content_type': 'html'},
|
||||||
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1,
|
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': False,
|
||||||
'active_ids': [self.group_pigs_id, group_bird_id]})
|
'active_ids': [self.group_pigs_id, group_bird_id]})
|
||||||
compose = mail_compose.browse(cr, uid, compose_id)
|
compose = mail_compose.browse(cr, uid, compose_id)
|
||||||
# Test: content_subtype is html
|
# Test: content_subtype is html
|
||||||
|
@ -496,107 +529,114 @@ class test_mail(TestMailMockups):
|
||||||
self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
|
self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
|
||||||
self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
|
self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
|
||||||
|
|
||||||
def test_30_message_read(self):
|
# FP Note: to be reviewed to be more generic, not depending on the algorythm of
|
||||||
""" Tests designed for message_read. """
|
# message_read
|
||||||
# TDE NOTE: this test is not finished, as the message_read method is not fully specified.
|
#def test_30_message_read(self):
|
||||||
# It will be updated as soon as we have fixed specs !
|
# """ Tests designed for message_read. """
|
||||||
cr, uid = self.cr, self.uid
|
# # TDE NOTE: this test is not finished, as the message_read method is not fully specified.
|
||||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
# # It will be updated as soon as we have fixed specs !
|
||||||
|
# cr, uid = self.cr, self.uid
|
||||||
|
# group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||||
|
|
||||||
def _compare_structures(struct1, struct2, n=0):
|
# def _compare_structures(struct1, struct2, n=0):
|
||||||
# print '%scompare structure' % ('\t' * n)
|
# # print '%scompare structure' % ('\t' * n)
|
||||||
self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect')
|
# # self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect')
|
||||||
for x in range(len(struct1)):
|
|
||||||
# print '%s' % ('\t' * n), struct1[x]['id'], struct2[x]['id'], struct1[x].get('subject') or ''
|
|
||||||
self.assertEqual(struct1[x]['id'], struct2[x]['id'], 'message_read failure %s' % struct1[x].get('subject'))
|
|
||||||
_compare_structures(struct1[x]['child_ids'], struct2[x]['child_ids'], n + 1)
|
|
||||||
# print '%send compare' % ('\t' * n)
|
|
||||||
|
|
||||||
# ----------------------------------------
|
# for x in range(len(struct1)):
|
||||||
# CASE1: Flattening test
|
# if struct1[x].get('type') == 'expandable':
|
||||||
# ----------------------------------------
|
# continue
|
||||||
|
# # print '%s' % ('\t' * n), struct1[x]['id'], struct1[x]['child_nbr'], struct2[x]['id'], struct2[x].get('child_nbr', 'XX'), struct1[x].get('subject') or ''
|
||||||
|
# self.assertEqual(struct1[x]['id'], struct2[x]['id'], 'message_read failure %s' % struct1[x].get('subject'))
|
||||||
|
# _compare_structures(struct1[x]['child_ids'], struct2[x]['child_ids'], n + 1)
|
||||||
|
# # print '%send compare' % ('\t' * n)
|
||||||
|
|
||||||
# Create dummy message structure
|
# # ----------------------------------------
|
||||||
import copy
|
# # CASE1: Flattening test
|
||||||
tree = [{'id': 2, 'child_ids': [
|
# # ----------------------------------------
|
||||||
{'id': 6, 'child_ids': [
|
|
||||||
{'id': 8, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
]},
|
|
||||||
{'id': 1, 'child_ids':[
|
|
||||||
{'id': 7, 'child_ids': [
|
|
||||||
{'id': 9, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
{'id': 4, 'child_ids': [
|
|
||||||
{'id': 10, 'child_ids': []},
|
|
||||||
{'id': 5, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
{'id': 3, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
]
|
|
||||||
# Test: completely flat
|
|
||||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 0)
|
|
||||||
self.assertEqual(len(new_tree), 10, 'message_read_tree_flatten wrong in flat')
|
|
||||||
# Test: 1 thread level
|
|
||||||
tree_test = [{'id': 2, 'child_ids': [
|
|
||||||
{'id': 8, 'child_ids': []}, {'id': 6, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
{'id': 1, 'child_ids': [
|
|
||||||
{'id': 10, 'child_ids': []}, {'id': 9, 'child_ids': []},
|
|
||||||
{'id': 7, 'child_ids': []}, {'id': 5, 'child_ids': []},
|
|
||||||
{'id': 4, 'child_ids': []}, {'id': 3, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
]
|
|
||||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 1)
|
|
||||||
_compare_structures(new_tree, tree_test)
|
|
||||||
# Test: 2 thread levels
|
|
||||||
new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 2)
|
|
||||||
_compare_structures(new_tree, tree)
|
|
||||||
|
|
||||||
# ----------------------------------------
|
# # Create dummy message structure
|
||||||
# CASE2: message_read test
|
# import copy
|
||||||
# ----------------------------------------
|
# tree = [{'id': 2, 'child_nbr': 1, 'child_ids': [
|
||||||
|
# {'id': 6, 'child_nbr': 1, 'child_ids': [
|
||||||
|
# {'id': 8, 'child_nbr': 0, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# ]},
|
||||||
|
# {'id': 1, 'child_nbr': 3, 'child_ids':[
|
||||||
|
# {'id': 7, 'child_nbr': 1, 'child_ids': [
|
||||||
|
# {'id': 9, 'child_nbr': 0, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# {'id': 4, 'child_nbr': 2, 'child_ids': [
|
||||||
|
# {'id': 10, 'child_nbr': 0, 'child_ids': []},
|
||||||
|
# {'id': 5, 'child_nbr': 0, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# {'id': 3, 'child_nbr': 0, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# ]
|
||||||
|
# # Test: completely flat
|
||||||
|
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 0, limit=15, add_expandable=False)
|
||||||
|
# _compare_structures(new_tree, new_tree)
|
||||||
|
# self.assertEqual(len(new_tree), 10, 'message_read_tree_flatten wrong in flat')
|
||||||
|
# # Test: 1 thread level
|
||||||
|
# tree_test = [{'id': 2, 'child_ids': [
|
||||||
|
# {'id': 8, 'child_ids': []}, {'id': 6, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# {'id': 1, 'child_ids': [
|
||||||
|
# {'id': 10, 'child_ids': []}, {'id': 9, 'child_ids': []},
|
||||||
|
# {'id': 7, 'child_ids': []}, {'id': 5, 'child_ids': []},
|
||||||
|
# {'id': 4, 'child_ids': []}, {'id': 3, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# ]
|
||||||
|
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 1, limit=15, add_expandable=False)
|
||||||
|
# _compare_structures(new_tree, tree_test)
|
||||||
|
# # Test: 2 thread levels
|
||||||
|
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 2, limit=15, add_expandable=False)
|
||||||
|
# _compare_structures(new_tree, tree)
|
||||||
|
|
||||||
# 1. Add a few messages to pigs group
|
# # ----------------------------------------
|
||||||
msgid1 = group_pigs.message_post(body='1', subject='1', parent_id=False)
|
# # CASE2: message_read test
|
||||||
msgid2 = group_pigs.message_post(body='2', subject='1-1', parent_id=msgid1)
|
# # ----------------------------------------
|
||||||
msgid3 = group_pigs.message_post(body='3', subject='1-2', parent_id=msgid1)
|
|
||||||
msgid4 = group_pigs.message_post(body='4', subject='2', parent_id=False)
|
|
||||||
msgid5 = group_pigs.message_post(body='5', subject='1-1-1', parent_id=msgid2)
|
|
||||||
msgid6 = group_pigs.message_post(body='6', subject='2-1', parent_id=msgid4)
|
|
||||||
|
|
||||||
# Test: read all messages flat
|
# # 1. Add a few messages to pigs group
|
||||||
tree_test = [{'id': msgid6, 'child_ids': []}, {'id': msgid5, 'child_ids': []},
|
# msgid1 = group_pigs.message_post(body='1', subject='1', parent_id=False)
|
||||||
{'id': msgid4, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
|
# msgid2 = group_pigs.message_post(body='2', subject='1-1', parent_id=msgid1)
|
||||||
{'id': msgid2, 'child_ids': []}, {'id': msgid1, 'child_ids': []}]
|
# msgid3 = group_pigs.message_post(body='3', subject='1-2', parent_id=msgid1)
|
||||||
tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=0, limit=10)
|
# msgid4 = group_pigs.message_post(body='4', subject='2', parent_id=False)
|
||||||
_compare_structures(tree, tree_test)
|
# msgid5 = group_pigs.message_post(body='5', subject='1-1-1', parent_id=msgid2)
|
||||||
# Test: read with 1 level of thread
|
# msgid6 = group_pigs.message_post(body='6', subject='2-1', parent_id=msgid4)
|
||||||
tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
|
|
||||||
{'id': msgid1, 'child_ids': [
|
|
||||||
{'id': msgid5, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
|
|
||||||
{'id': msgid2, 'child_ids': []},
|
|
||||||
]},
|
|
||||||
]
|
|
||||||
tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=1, limit=10)
|
|
||||||
_compare_structures(tree, tree_test)
|
|
||||||
# Test: read with 2 levels of thread
|
|
||||||
tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
|
|
||||||
{'id': msgid1, 'child_ids': [
|
|
||||||
{'id': msgid3, 'child_ids': []},
|
|
||||||
{'id': msgid2, 'child_ids': [{'id': msgid5, 'child_ids': []}, ]},
|
|
||||||
]},
|
|
||||||
]
|
|
||||||
tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=2, limit=10)
|
|
||||||
_compare_structures(tree, tree_test)
|
|
||||||
|
|
||||||
# 2. Test expandables
|
# # Test: read all messages flat
|
||||||
# TDE FIXME: add those tests when expandables are specified and implemented
|
# tree_test = [{'id': msgid6, 'child_ids': []}, {'id': msgid5, 'child_ids': []},
|
||||||
|
# {'id': msgid4, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
|
||||||
|
# {'id': msgid2, 'child_ids': []}, {'id': msgid1, 'child_ids': []}]
|
||||||
|
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=0, limit=15)
|
||||||
|
# _compare_structures(tree, tree_test)
|
||||||
|
# # Test: read with 1 level of thread
|
||||||
|
# tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
|
||||||
|
# {'id': msgid1, 'child_ids': [
|
||||||
|
# {'id': msgid5, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
|
||||||
|
# {'id': msgid2, 'child_ids': []},
|
||||||
|
# ]},
|
||||||
|
# ]
|
||||||
|
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=1, limit=15)
|
||||||
|
# _compare_structures(tree, tree_test)
|
||||||
|
# # Test: read with 2 levels of thread
|
||||||
|
# tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
|
||||||
|
# {'id': msgid1, 'child_ids': [
|
||||||
|
# {'id': msgid3, 'child_ids': []},
|
||||||
|
# {'id': msgid2, 'child_ids': [{'id': msgid5, 'child_ids': []}, ]},
|
||||||
|
# ]},
|
||||||
|
# ]
|
||||||
|
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=2, limit=15)
|
||||||
|
# _compare_structures(tree, tree_test)
|
||||||
|
|
||||||
|
# # 2. Test expandables
|
||||||
|
# # TDE FIXME: add those tests when expandables are specified and implemented
|
||||||
|
|
||||||
def test_40_needaction(self):
|
def test_40_needaction(self):
|
||||||
""" Tests for mail.message needaction. """
|
""" Tests for mail.message needaction. """
|
||||||
cr, uid = self.cr, self.uid
|
cr, uid = self.cr, self.uid
|
||||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||||
|
group_pigs_demo = self.mail_group.browse(cr, self.user_demo, self.group_pigs_id)
|
||||||
user_admin = self.res_users.browse(cr, uid, uid)
|
user_admin = self.res_users.browse(cr, uid, uid)
|
||||||
|
|
||||||
# Demo values: check unread notification = needaction on mail.message
|
# Demo values: check unread notification = needaction on mail.message
|
||||||
|
@ -607,9 +647,12 @@ class test_mail(TestMailMockups):
|
||||||
na_count = self.mail_message._needaction_count(cr, uid, domain=[])
|
na_count = self.mail_message._needaction_count(cr, uid, domain=[])
|
||||||
self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
|
self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
|
||||||
|
|
||||||
# Post 4 message on group_pigs
|
na_count1 = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
|
||||||
for dummy in range(4):
|
# Post 2 message on group_pigs as admin, 3 messages as demo user
|
||||||
group_pigs.message_post(body='My Body')
|
for dummy in range(2):
|
||||||
|
group_pigs.message_post(body='My Body', subtype='mt_comment')
|
||||||
|
for dummy in range(3):
|
||||||
|
group_pigs_demo.message_post(body='My Demo Body', subtype='mt_comment')
|
||||||
|
|
||||||
# Check there are 4 new needaction on mail.message
|
# Check there are 4 new needaction on mail.message
|
||||||
notif_ids = self.mail_notification.search(cr, uid, [
|
notif_ids = self.mail_notification.search(cr, uid, [
|
||||||
|
@ -621,7 +664,19 @@ class test_mail(TestMailMockups):
|
||||||
|
|
||||||
# Check there are 4 needaction on mail.message with particular domain
|
# Check there are 4 needaction on mail.message with particular domain
|
||||||
na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
|
na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
|
||||||
self.assertEqual(na_count, 4, 'posted message count does not match needaction count')
|
notif_ids = self.mail_notification.search(cr, uid, [
|
||||||
|
('partner_id', '=', user_admin.partner_id.id),
|
||||||
|
('read', '=', False),
|
||||||
|
('message_id.model','=','mail.group'),
|
||||||
|
('message_id.res_id','=',self.group_pigs_id)
|
||||||
|
])
|
||||||
|
self.assertEqual(len(notif_ids), na_count, 'posted message count does not match needaction count')
|
||||||
|
|
||||||
|
na_count3 = self.mail_message._needaction_count(cr, self.user_demo, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
|
||||||
|
self.assertEqual(na_count3-na_count1, 0, 'demo has 0 message: not a follower and do not follow his own messages')
|
||||||
|
|
||||||
|
na_count2 = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
|
||||||
|
self.assertEqual(na_count2-na_count1, 3, 'admin has 3 messages: 0 from itself as they are marked as read, 3 from demo')
|
||||||
|
|
||||||
def test_50_thread_parent_resolution(self):
|
def test_50_thread_parent_resolution(self):
|
||||||
"""Verify parent/child relationships are correctly established when processing incoming mails"""
|
"""Verify parent/child relationships are correctly established when processing incoming mails"""
|
||||||
|
@ -636,15 +691,18 @@ class test_mail(TestMailMockups):
|
||||||
# 1. In-Reply-To header
|
# 1. In-Reply-To header
|
||||||
reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
|
reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
|
||||||
extra='In-Reply-To: %s' % msg1.message_id)
|
extra='In-Reply-To: %s' % msg1.message_id)
|
||||||
self.mail_thread.message_process(cr, uid, None, reply_msg)
|
self.mail_group.message_process(cr, uid, None, reply_msg)
|
||||||
|
|
||||||
# 2. References header
|
# 2. References header
|
||||||
reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
|
reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
|
||||||
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
|
extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
|
||||||
self.mail_thread.message_process(cr, uid, None, reply_msg2)
|
self.mail_group.message_process(cr, uid, None, reply_msg2)
|
||||||
|
|
||||||
# 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
|
# 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
|
||||||
reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
|
reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
|
||||||
extra='', subject='Re: [%s] 1' % self.group_pigs_id)
|
extra='', subject='Re: [%s] 1' % self.group_pigs_id)
|
||||||
self.mail_thread.message_process(cr, uid, 'mail.group', reply_msg3)
|
self.mail_group.message_process(cr, uid, 'mail.group', reply_msg3)
|
||||||
|
|
||||||
group_pigs.refresh()
|
group_pigs.refresh()
|
||||||
msg1.refresh()
|
msg1.refresh()
|
||||||
self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
|
self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
|
||||||
|
@ -653,8 +711,8 @@ class test_mail(TestMailMockups):
|
||||||
def test_60_vote(self):
|
def test_60_vote(self):
|
||||||
""" Test designed for the vote/unvote feature. """
|
""" Test designed for the vote/unvote feature. """
|
||||||
cr, uid = self.cr, self.uid
|
cr, uid = self.cr, self.uid
|
||||||
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
|
||||||
user_admin = self.res_users.browse(cr, uid, uid)
|
user_admin = self.res_users.browse(cr, uid, uid)
|
||||||
|
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
|
||||||
msg1 = group_pigs.message_post(body='My Body', subject='1')
|
msg1 = group_pigs.message_post(body='My Body', subject='1')
|
||||||
msg1 = self.mail_message.browse(cr, uid, msg1)
|
msg1 = self.mail_message.browse(cr, uid, msg1)
|
||||||
|
|
||||||
|
|
|
@ -102,53 +102,53 @@ class test_mail_access_rights(test_mail.TestMailMockups):
|
||||||
""" Test mail_message search override about access rights. """
|
""" Test mail_message search override about access rights. """
|
||||||
self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True')
|
self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True')
|
||||||
|
|
||||||
def test_10_mail_flow_access_rights(self):
|
# def test_10_mail_flow_access_rights(self):
|
||||||
""" Test a Chatter-looks alike flow. """
|
# """ Test a Chatter-looks alike flow. """
|
||||||
cr, uid = self.cr, self.uid
|
# cr, uid = self.cr, self.uid
|
||||||
partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
|
# partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id
|
||||||
user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
|
# user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id
|
||||||
|
|
||||||
# Prepare groups: Pigs (employee), Jobs (public)
|
# # Prepare groups: Pigs (employee), Jobs (public)
|
||||||
self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
|
# self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
|
||||||
self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'})
|
# self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'})
|
||||||
|
|
||||||
# ----------------------------------------
|
# # ----------------------------------------
|
||||||
# CASE1: Bert, without groups
|
# # CASE1: Bert, without groups
|
||||||
# ----------------------------------------
|
# # ----------------------------------------
|
||||||
# Do: Bert creates a group, should crash because perm_create only for employees
|
# # Do: Bert creates a group, should crash because perm_create only for employees
|
||||||
self.assertRaises(except_orm,
|
# self.assertRaises(except_orm,
|
||||||
self.mail_group.create,
|
# self.mail_group.create,
|
||||||
cr, user_bert_id, {'name': 'Bert\'s Group'})
|
# cr, user_bert_id, {'name': 'Bert\'s Group'})
|
||||||
# Do: Bert reads Jobs basic fields, ok because public = read access on the group
|
# # Do: Bert reads Jobs basic fields, ok because public = read access on the group
|
||||||
self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description'])
|
# self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description'])
|
||||||
# Do: Bert browse Pigs, ok (no direct browse of partners)
|
# # Do: Bert browse Pigs, ok (no direct browse of partners)
|
||||||
self.mail_group.browse(cr, user_bert_id, self.group_jobs_id)
|
# self.mail_group.browse(cr, user_bert_id, self.group_jobs_id)
|
||||||
# Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages
|
# # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages
|
||||||
jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids']
|
# jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids']
|
||||||
self.mail_message.read(cr, user_bert_id, jobs_message_ids)
|
# self.mail_message.read(cr, user_bert_id, jobs_message_ids)
|
||||||
# Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager
|
# # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager
|
||||||
jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids']
|
# jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids']
|
||||||
self.assertRaises(except_orm,
|
# self.assertRaises(except_orm,
|
||||||
self.res_partner.read,
|
# self.res_partner.read,
|
||||||
cr, user_bert_id, jobs_followers_ids)
|
# cr, user_bert_id, jobs_followers_ids)
|
||||||
# Do: Bert comments Jobs, ko because no write access on the group and not in the followers
|
# # Do: Bert comments Jobs, ko because no write access on the group and not in the followers
|
||||||
self.assertRaises(except_orm,
|
# self.assertRaises(except_orm,
|
||||||
self.mail_group.message_post,
|
# self.mail_group.message_post,
|
||||||
cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
# cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
||||||
# Do: add Bert to jobs followers
|
# # Do: add Bert to jobs followers
|
||||||
self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id])
|
# self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id])
|
||||||
# Do: Bert comments Jobs, ok because he is now in the followers
|
# # Do: Bert comments Jobs, ok because he is now in the followers
|
||||||
self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
# self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs')
|
||||||
|
|
||||||
# Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group
|
# # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group
|
||||||
self.assertRaises(except_orm,
|
# self.assertRaises(except_orm,
|
||||||
self.mail_group.read,
|
# self.mail_group.read,
|
||||||
cr, user_bert_id, self.group_pigs_id)
|
# cr, user_bert_id, self.group_pigs_id)
|
||||||
|
|
||||||
# ----------------------------------------
|
# # ----------------------------------------
|
||||||
# CASE1: Raoul, employee
|
# # CASE1: Raoul, employee
|
||||||
# ----------------------------------------
|
# # ----------------------------------------
|
||||||
# Do: Bert read Pigs, ok because public
|
# # Do: Bert read Pigs, ok because public
|
||||||
self.mail_group.read(cr, user_raoul_id, self.group_pigs_id)
|
# self.mail_group.read(cr, user_raoul_id, self.group_pigs_id)
|
||||||
# Do: Bert read Jobs, ok because group_public_id = employee
|
# # Do: Bert read Jobs, ok because group_public_id = employee
|
||||||
self.mail_group.read(cr, user_raoul_id, self.group_jobs_id)
|
# self.mail_group.read(cr, user_raoul_id, self.group_jobs_id)
|
||||||
|
|
|
@ -102,9 +102,9 @@ class mail_compose_message(osv.TransientModel):
|
||||||
'partner_ids': fields.many2many('res.partner',
|
'partner_ids': fields.many2many('res.partner',
|
||||||
'mail_compose_message_res_partner_rel',
|
'mail_compose_message_res_partner_rel',
|
||||||
'wizard_id', 'partner_id', 'Additional contacts'),
|
'wizard_id', 'partner_id', 'Additional contacts'),
|
||||||
'attachment_ids': fields.many2many('ir.attachment',
|
'attachment_ids': fields.one2many('ir.attachment', 'res_id',
|
||||||
'mail_compose_message_ir_attachments_rel',
|
domain=lambda self: [('res_model', '=', self._name)],
|
||||||
'wizard_id', 'attachment_id', 'Attachments'),
|
string='Attachments'),
|
||||||
'filter_id': fields.many2one('ir.filters', 'Filters'),
|
'filter_id': fields.many2one('ir.filters', 'Filters'),
|
||||||
'body_text': fields.text('Plain-text Contents'),
|
'body_text': fields.text('Plain-text Contents'),
|
||||||
'content_subtype': fields.char('Message content subtype', size=32, readonly=1,
|
'content_subtype': fields.char('Message content subtype', size=32, readonly=1,
|
||||||
|
@ -219,19 +219,29 @@ class mail_compose_message(osv.TransientModel):
|
||||||
email(s), rendering any template patterns on the fly if needed. """
|
email(s), rendering any template patterns on the fly if needed. """
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
print '**', context
|
||||||
active_ids = context.get('active_ids')
|
active_ids = context.get('active_ids')
|
||||||
|
|
||||||
for wizard in self.browse(cr, uid, ids, context=context):
|
for wizard in self.browse(cr, uid, ids, context=context):
|
||||||
mass_mail_mode = wizard.composition_mode == 'mass_mail'
|
mass_mail_mode = wizard.composition_mode == 'mass_mail'
|
||||||
active_model_pool = self.pool.get(wizard.model if wizard.model else 'mail.thread')
|
active_model_pool = self.pool.get(wizard.model if wizard.model else 'mail.thread')
|
||||||
|
|
||||||
|
if wizard.content_subtype == 'html':
|
||||||
|
if not wizard.body:
|
||||||
|
return False
|
||||||
|
body = wizard.body
|
||||||
|
else: # wizard.content_subtype == 'plain':
|
||||||
|
if not wizard.body_text:
|
||||||
|
return False
|
||||||
|
body = '<pre>%s</pre>' % tools.ustr(wizard.body_text or '')
|
||||||
|
|
||||||
# wizard works in batch mode: [res_id] or active_ids
|
# wizard works in batch mode: [res_id] or active_ids
|
||||||
res_ids = active_ids if mass_mail_mode and wizard.model and active_ids else [wizard.res_id]
|
res_ids = active_ids if mass_mail_mode and wizard.model and active_ids else [wizard.res_id]
|
||||||
for res_id in res_ids:
|
for res_id in res_ids:
|
||||||
# default values, according to the wizard options
|
# default values, according to the wizard options
|
||||||
post_values = {
|
post_values = {
|
||||||
'subject': wizard.subject if wizard.content_subtype == 'html' else False,
|
'subject': wizard.subject if wizard.content_subtype == 'html' else False,
|
||||||
'body': wizard.body if wizard.content_subtype == 'html' else '<pre>%s</pre>' % tools.ustr(wizard.body_text),
|
'body': body,
|
||||||
'parent_id': wizard.parent_id and wizard.parent_id.id,
|
'parent_id': wizard.parent_id and wizard.parent_id.id,
|
||||||
'partner_ids': [(4, partner.id) for partner in wizard.partner_ids],
|
'partner_ids': [(4, partner.id) for partner in wizard.partner_ids],
|
||||||
'attachments': [(attach.datas_fname or attach.name, base64.b64decode(attach.datas)) for attach in wizard.attachment_ids],
|
'attachments': [(attach.datas_fname or attach.name, base64.b64decode(attach.datas)) for attach in wizard.attachment_ids],
|
||||||
|
@ -245,11 +255,13 @@ class mail_compose_message(osv.TransientModel):
|
||||||
post_values['attachments'] += new_attachments
|
post_values['attachments'] += new_attachments
|
||||||
post_values.update(email_dict)
|
post_values.update(email_dict)
|
||||||
# post the message
|
# post the message
|
||||||
active_model_pool.message_post(cr, uid, [res_id], type='comment', context=context, **post_values)
|
id=active_model_pool.message_post(cr, uid, [res_id], type='comment', subtype='mt_comment', context=context, **post_values)
|
||||||
# post process: update attachments, because id is not necessarily known when adding attachments in Chatter
|
|
||||||
self.pool.get('ir.attachment').write(cr, uid, [attach.id for attach in wizard.attachment_ids], {'res_id': wizard.id}, context=context)
|
|
||||||
|
|
||||||
return {'type': 'ir.actions.act_window_close'}
|
# post process: update attachments, because id is not necessarily known when adding attachments in Chatter
|
||||||
|
# self.pool.get('ir.attachment').write(cr, uid, [attach.id for attach in wizard.attachment_ids], {
|
||||||
|
# 'res_id': wizard.id, 'res_model': wizard.model or False}, context=context)
|
||||||
|
|
||||||
|
return {'type': 'ir.actions.act_window_close', 'res_model':'mail.compose.message', 'id': id}
|
||||||
|
|
||||||
def render_message(self, cr, uid, wizard, res_id, context=None):
|
def render_message(self, cr, uid, wizard, res_id, context=None):
|
||||||
""" Generate an email from the template for given (wizard.model, res_id)
|
""" Generate an email from the template for given (wizard.model, res_id)
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
<div colspan="2" class="oe_mail_compose_message_attachments"/>
|
<div colspan="2" class="oe_mail_compose_message_attachments"/>
|
||||||
<!-- buttons, with as few Chatter logic as possible -->
|
<!-- buttons, with as few Chatter logic as possible -->
|
||||||
<div>
|
<div>
|
||||||
<button name="send_mail" string="Post" type="object"
|
<button name="send_mail" string="Post message" type="object"
|
||||||
class="oe_mail_compose_message_button_send"/>
|
class="oe_mail_compose_message_button_send"/>
|
||||||
</div>
|
</div>
|
||||||
<div class='oe_mail_compose_message_icons'>
|
<div class='oe_mail_compose_message_icons'>
|
||||||
|
|
|
@ -26,6 +26,6 @@ From the Manufacturing Settings, you can choose to compute production schedules
|
||||||
<field name="number_next">1</field>
|
<field name="number_next">1</field>
|
||||||
<field name="number_increment">1</field>
|
<field name="number_increment">1</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -409,9 +409,8 @@
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
@ -798,7 +797,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -58,6 +58,7 @@ So, that we can compare the theoretic delay and real delay.
|
||||||
'depends': ['mrp'],
|
'depends': ['mrp'],
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
'mrp_operation_data.xml',
|
||||||
'mrp_operations_workflow.xml',
|
'mrp_operations_workflow.xml',
|
||||||
'mrp_operations_view.xml',
|
'mrp_operations_view.xml',
|
||||||
'mrp_operations_report.xml',
|
'mrp_operations_report.xml',
|
||||||
|
@ -65,7 +66,7 @@ So, that we can compare the theoretic delay and real delay.
|
||||||
'process/mrp_operation_process.xml',
|
'process/mrp_operation_process.xml',
|
||||||
'mrp_operations_workflow_instance.xml'
|
'mrp_operations_workflow_instance.xml'
|
||||||
],
|
],
|
||||||
'demo': ['mrp_operation_data.xml',
|
'demo': [
|
||||||
'mrp_operations_demo.yml'
|
'mrp_operations_demo.yml'
|
||||||
],
|
],
|
||||||
'test': [
|
'test': [
|
||||||
|
|
|
@ -107,7 +107,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -43,6 +43,7 @@ The following topics should be covered by this module:
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'security/mrp_repair_security.xml',
|
'security/mrp_repair_security.xml',
|
||||||
|
'mrp_repair_data.xml',
|
||||||
'mrp_repair_sequence.xml',
|
'mrp_repair_sequence.xml',
|
||||||
'wizard/mrp_repair_cancel_view.xml',
|
'wizard/mrp_repair_cancel_view.xml',
|
||||||
'wizard/mrp_repair_make_invoice_view.xml',
|
'wizard/mrp_repair_make_invoice_view.xml',
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -189,7 +189,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -108,22 +108,21 @@
|
||||||
|
|
||||||
<!-- New note Form View -->
|
<!-- New note Form View -->
|
||||||
<record model="ir.ui.view" id="view_note_note_form">
|
<record model="ir.ui.view" id="view_note_note_form">
|
||||||
<field name="name">note.note.form</field>
|
<field name="name">note.note.form</field>
|
||||||
<field name="model">note.note</field>
|
<field name="model">note.note</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Note" version="7.0">
|
<form string="Note" version="7.0">
|
||||||
<header>
|
<header>
|
||||||
<field name="tag_ids" widget="many2many_tags" class="oe_inline" placeholder="Tags"/>
|
<field name="tag_ids" widget="many2many_tags" class="oe_inline" placeholder="Tags"/>
|
||||||
<field name="stage_id" domain="[('user_id','=',uid)]" widget="statusbar" clickable="1"/>
|
<field name="stage_id" domain="[('user_id','=',uid)]" widget="statusbar" clickable="1"/>
|
||||||
</header>
|
</header>
|
||||||
<field name="memo" widget="html"/><!-- editor_width="100%%" editor_height="60%%" -->
|
<field name="memo" widget="html"/><!-- editor_width="100%%" editor_height="60%%" -->
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field class="oe_chatter" name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
</field>
|
||||||
</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Search note -->
|
<!-- Search note -->
|
||||||
|
|
|
@ -498,22 +498,22 @@ class procurement_order(osv.osv):
|
||||||
return obj_id
|
return obj_id
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>created</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement <b>created</b>."), context=context)
|
||||||
|
|
||||||
def confirm_send_note(self, cr, uid, ids, context=None):
|
def confirm_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>confirmed</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement <b>confirmed</b>."), context=context)
|
||||||
|
|
||||||
def running_send_note(self, cr, uid, ids, context=None):
|
def running_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>running</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement set to <b>running</b>."), context=context)
|
||||||
|
|
||||||
def ready_send_note(self, cr, uid, ids, context=None):
|
def ready_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been set to <b>ready</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement set to <b>ready</b>."), context=context)
|
||||||
|
|
||||||
def cancel_send_note(self, cr, uid, ids, context=None):
|
def cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>cancelled</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement <b>cancelled</b>."), context=context)
|
||||||
|
|
||||||
def done_send_note(self, cr, uid, ids, context=None):
|
def done_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Procurement has been <b>done</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Procurement <b>done</b>."), context=context)
|
||||||
|
|
||||||
procurement_order()
|
procurement_order()
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -203,7 +203,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -519,20 +519,16 @@ def Project():
|
||||||
return self.message_post(cr, uid, ids, body=_("Project has been <b>created</b>."), context=context)
|
return self.message_post(cr, uid, ids, body=_("Project has been <b>created</b>."), context=context)
|
||||||
|
|
||||||
def set_open_send_note(self, cr, uid, ids, context=None):
|
def set_open_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Project has been <b>opened</b>.")
|
return self.message_post(cr, uid, ids, body=_("Project has been <b>opened</b>."), context=context)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
|
||||||
|
|
||||||
def set_pending_send_note(self, cr, uid, ids, context=None):
|
def set_pending_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Project is now <b>pending</b>.")
|
return self.message_post(cr, uid, ids, body=_("Project is now <b>pending</b>."), context=context)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
|
||||||
|
|
||||||
def set_cancel_send_note(self, cr, uid, ids, context=None):
|
def set_cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Project has been <b>cancelled</b>.")
|
return self.message_post(cr, uid, ids, body=_("Project has been <b>canceled</b>."), context=context)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
|
||||||
|
|
||||||
def set_close_send_note(self, cr, uid, ids, context=None):
|
def set_close_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Project has been <b>closed</b>.")
|
return self.message_post(cr, uid, ids, body=_("Project has been <b>closed</b>."), context=context)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
|
||||||
|
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
# if alias_model has been changed, update alias_model_id accordingly
|
# if alias_model has been changed, update alias_model_id accordingly
|
||||||
|
@ -1100,10 +1096,10 @@ class task(base_stage, osv.osv):
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
task_id = super(task, self).create(cr, uid, vals, context=context)
|
task_id = super(task, self).create(cr, uid, vals, context=context)
|
||||||
project_id = self.browse(cr, uid, task_id, context=context).project_id
|
task_record = self.browse(cr, uid, task_id, context=context)
|
||||||
if project_id:
|
if task_record.project_id:
|
||||||
followers = [follower.id for follower in project_id.message_follower_ids]
|
project_follower_ids = [follower.id for follower in task_record.project_id.message_follower_ids]
|
||||||
self.message_subscribe(cr, uid, [task_id], followers, context=context)
|
self.message_subscribe(cr, uid, [task_id], project_follower_ids, context=context)
|
||||||
self._store_history(cr, uid, [task_id], context=context)
|
self._store_history(cr, uid, [task_id], context=context)
|
||||||
self.create_send_note(cr, uid, [task_id], context=context)
|
self.create_send_note(cr, uid, [task_id], context=context)
|
||||||
return task_id
|
return task_id
|
||||||
|
@ -1235,14 +1231,14 @@ class task(base_stage, osv.osv):
|
||||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||||
""" Override of the (void) default notification method. """
|
""" Override of the (void) default notification method. """
|
||||||
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||||
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
return self.message_post(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % (stage_name),
|
||||||
|
context=context)
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
return self.message_post(cr, uid, ids, body=_("Task has been <b>created</b>."), context=context)
|
return self.message_post(cr, uid, ids, body=_("Task has been <b>created</b>."), context=context)
|
||||||
|
|
||||||
def case_draft_send_note(self, cr, uid, ids, context=None):
|
def case_draft_send_note(self, cr, uid, ids, context=None):
|
||||||
msg = _('Task has been set as <b>draft</b>.')
|
return self.message_post(cr, uid, ids, body=_('Task has been set as <b>draft</b>.'), context=context)
|
||||||
return self.message_post(cr, uid, ids, body=msg, context=context)
|
|
||||||
|
|
||||||
def do_delegation_send_note(self, cr, uid, ids, context=None):
|
def do_delegation_send_note(self, cr, uid, ids, context=None):
|
||||||
for task in self.browse(cr, uid, ids, context=context):
|
for task in self.browse(cr, uid, ids, context=context):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
<data noupdate="1">
|
<data>
|
||||||
<!-- This will set the unit of measure used in projects and tasks.-->
|
<!-- This will set the unit of measure used in projects and tasks.-->
|
||||||
<record id="base.main_company" model="res.company">
|
<record id="base.main_company" model="res.company">
|
||||||
<field name="project_time_mode_id" ref="product.product_uom_hour"></field>
|
<field name="project_time_mode_id" ref="product.product_uom_hour"></field>
|
||||||
|
@ -84,6 +84,42 @@
|
||||||
<field name="fold" eval="True"/>
|
<field name="fold" eval="True"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- mail: subtypes -->
|
||||||
|
<record id="mt_project_new" model="mail.message.subtype">
|
||||||
|
<field name="name">New Task</field>
|
||||||
|
<field name="res_model">project.project</field>
|
||||||
|
<field name="default" eval="False"/>
|
||||||
|
</record>
|
||||||
|
<record id="mt_project_closed" model="mail.message.subtype">
|
||||||
|
<field name="name">Task Closed</field>
|
||||||
|
<field name="res_model">project.project</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_project_canceled" model="mail.message.subtype">
|
||||||
|
<field name="name">Task Canceled</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_project_stage" model="mail.message.subtype">
|
||||||
|
<field name="name">Task Stage Changed</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="mt_task_new" model="mail.message.subtype">
|
||||||
|
<field name="name">New Task</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_task_closed" model="mail.message.subtype">
|
||||||
|
<field name="name">Task Closed</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_task_canceled" model="mail.message.subtype">
|
||||||
|
<field name="name">Task canceled</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
<record id="mt_task_change" model="mail.message.subtype">
|
||||||
|
<field name="name">Task Stage Changed</field>
|
||||||
|
<field name="res_model">project.task</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<!-- notify all employees of module installation -->
|
<!-- notify all employees of module installation -->
|
||||||
<record model="mail.message" id="module_install_notification">
|
<record model="mail.message" id="module_install_notification">
|
||||||
<field name="model">mail.group</field>
|
<field name="model">mail.group</field>
|
||||||
|
|
|
@ -150,7 +150,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers" help="Follow this project to automatically follow all related tasks and issues."/>
|
<field name="message_follower_ids" widget="mail_followers" help="Follow this project to automatically follow all related tasks and issues."/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -468,7 +467,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -511,7 +511,7 @@ class project_issue(base_stage, osv.osv):
|
||||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||||
""" Override of the (void) default notification method. """
|
""" Override of the (void) default notification method. """
|
||||||
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||||
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
return self.message_post(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), subtype="mt_issue_new", context=context)
|
||||||
|
|
||||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||||
""" Override of default prefix for notifications. """
|
""" Override of default prefix for notifications. """
|
||||||
|
@ -523,7 +523,7 @@ class project_issue(base_stage, osv.osv):
|
||||||
|
|
||||||
def create_send_note(self, cr, uid, ids, context=None):
|
def create_send_note(self, cr, uid, ids, context=None):
|
||||||
message = _("Project issue <b>created</b>.")
|
message = _("Project issue <b>created</b>.")
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
return self.message_post(cr, uid, ids, body=message, subtype="mt_issue_new", context=context)
|
||||||
|
|
||||||
def case_escalate_send_note(self, cr, uid, ids, context=None):
|
def case_escalate_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
|
|
|
@ -42,5 +42,21 @@ You can record issues, assign them to a responsible person, and keep track of th
|
||||||
Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</field>
|
Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Mail subtypes -->
|
||||||
|
<record id="mail.mt_issue_new" model="mail.message.subtype">
|
||||||
|
<field name="name">created</field>
|
||||||
|
<field name="res_model">project.issue</field>
|
||||||
|
<field name="default" eval="False"/>
|
||||||
|
</record>
|
||||||
|
<record id="mail.mt_issue_new" model="mail.message.subtype">
|
||||||
|
<field name="name">stage change</field>
|
||||||
|
<field name="res_model">project.issue</field>
|
||||||
|
<field name="default" eval="False"/>
|
||||||
|
</record>
|
||||||
|
<record id="mail.mt_issue_closed" model="mail.message.subtype">
|
||||||
|
<field name="name">closed</field>
|
||||||
|
<field name="res_model">project.issue</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -161,7 +161,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -285,7 +285,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -92,13 +92,13 @@ class purchase_requisition(osv.osv):
|
||||||
|
|
||||||
def in_progress_send_note(self, cr, uid, ids, context=None):
|
def in_progress_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Draft Requisition has been <b>sent to suppliers</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Draft Requisition has been <b>sent to suppliers</b>."), context=context)
|
||||||
|
|
||||||
def reset_send_note(self, cr, uid, ids, context=None):
|
def reset_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been set to <b>draft</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been set to <b>draft</b>."), context=context)
|
||||||
|
|
||||||
def done_to_send_note(self, cr, uid, ids, context=None):
|
def done_to_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>done</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>done</b>."), context=context)
|
||||||
|
|
||||||
def cancel_send_note(self, cr, uid, ids, context=None):
|
def cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>cancelled</b>."), context=context)
|
self.message_post(cr, uid, ids, body=_("Purchase Requisition has been <b>cancelled</b>."), context=context)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
<data noupdate="1">
|
<data noupdate="1">
|
||||||
<function
|
<function
|
||||||
eval="('default',False,'warehouse_id', [('purchase.requisition', False)], ref('stock.warehouse0'), True, False, False, False, True)"
|
eval="('default',False,'warehouse_id', [('purchase.requisition', False)], ref('stock.warehouse0'), True, False, False, False, True)"
|
||||||
id="purchase_default_set"
|
id="purchase_default_set"
|
||||||
model="ir.values"
|
model="ir.values"
|
||||||
|
|
|
@ -102,9 +102,8 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
@ -310,7 +310,6 @@
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1450,7 +1450,7 @@ class stock_picking(osv.osv):
|
||||||
'internal': _("Products have been <b>moved</b>."),
|
'internal': _("Products have been <b>moved</b>."),
|
||||||
}
|
}
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
self.message_post(cr, uid, [obj.id], body=type_dict.get(obj.type, _('Products have been moved.')), context=context)
|
self.message_post(cr, uid, [obj.id], body=_("Products have been <b>%s</b>.") % (type_dict.get(obj.type, 'move done')), context=context)
|
||||||
|
|
||||||
def ship_cancel_send_note(self, cr, uid, ids, context=None):
|
def ship_cancel_send_note(self, cr, uid, ids, context=None):
|
||||||
for obj in self.browse(cr, uid, ids, context=context):
|
for obj in self.browse(cr, uid, ids, context=context):
|
||||||
|
|
|
@ -914,7 +914,6 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1041,7 +1040,6 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
<field name="message_is_follower" invisible="1"/>
|
|
||||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue