summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric van der Essen <fva@openerp.com>2012-10-22 15:28:02 +0200
committerFrédéric van der Essen <fva@openerp.com>2012-10-22 15:28:02 +0200
commitea3d65f0cba87a7698bab3036df4d4aa5be0bb3e (patch)
treeab06c0260020e7a8891b304e519cd7d804131a0a
parent09d5c74d95c6db0a2247c131d15ca17725b73c46 (diff)
parent87afad0a4df19a38787e452f685110766099fa2c (diff)
[MERGE] mail: from chm
bzr revid: fva@openerp.com-20121022132802-u02hg6ps4dvc4auu
-rw-r--r--addons/account/project/project_view.xml2
-rw-r--r--addons/anonymization/i18n/mn.po213
-rw-r--r--addons/hr/i18n/lt.po16
-rw-r--r--addons/hr_attendance/report/attendance_by_month.py2
-rw-r--r--addons/hr_attendance/report/timesheet.py2
-rw-r--r--addons/hr_attendance/wizard/hr_attendance_byweek.py1
-rw-r--r--addons/hr_recruitment/hr_recruitment_data.xml2
-rw-r--r--addons/hr_timesheet/i18n/mk.po642
-rw-r--r--addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py2
-rw-r--r--addons/hr_timesheet_invoice/hr_timesheet_invoice.py2
-rw-r--r--addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml4
-rw-r--r--addons/hr_timesheet_sheet/hr_timesheet_sheet.py2
-rw-r--r--addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml4
-rw-r--r--addons/hr_timesheet_sheet/report/timesheet_report.py4
-rw-r--r--addons/mail/mail_message.py98
-rw-r--r--addons/mail/mail_message_view.xml2
-rw-r--r--addons/mail/mail_thread.py16
-rw-r--r--addons/mail/res_users.py13
-rw-r--r--addons/mail/security/mail_security.xml2
-rw-r--r--addons/mail/static/src/css/mail.css3
-rw-r--r--addons/mail/static/src/js/mail.js696
-rw-r--r--addons/mail/static/src/js/mail_followers.js17
-rw-r--r--addons/mail/static/src/xml/mail.xml79
-rw-r--r--addons/mail/tests/test_mail.py14
-rw-r--r--addons/mail/wizard/mail_compose_message_view.xml14
-rw-r--r--addons/mrp/security/ir.model.access.csv1
-rw-r--r--addons/product/i18n/es_EC.po2
-rw-r--r--addons/sale/i18n/hu.po21
-rw-r--r--addons/stock/security/stock_security.xml1
29 files changed, 1417 insertions, 460 deletions
diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml
index 70db95425b1..342663e700f 100644
--- a/addons/account/project/project_view.xml
+++ b/addons/account/project/project_view.xml
@@ -160,7 +160,7 @@
<field name="name">account.analytic.line.tree</field>
<field name="model">account.analytic.line</field>
<field name="arch" type="xml">
- <tree editable="top" string="Analytic Entries">
+ <tree string="Analytic Entries">
<field name="date"/>
<field name="ref" invisible="context.get('to_invoice', False)"/>
<field name="name"/>
diff --git a/addons/anonymization/i18n/mn.po b/addons/anonymization/i18n/mn.po
new file mode 100644
index 00000000000..cd54ad8ef6c
--- /dev/null
+++ b/addons/anonymization/i18n/mn.po
@@ -0,0 +1,213 @@
+# Mongolian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2012-02-08 00:35+0000\n"
+"PO-Revision-Date: 2012-10-22 02:35+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Mongolian <mn@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-10-22 04:40+0000\n"
+"X-Generator: Launchpad (build 16165)\n"
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
+msgid "ir.model.fields.anonymize.wizard"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_name:0
+msgid "Field Name"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_id:0
+msgid "Field"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,state:0
+#: field:ir.model.fields.anonymize.wizard,state:0
+msgid "State"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_import:0
+msgid "Import"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
+msgid "ir.model.fields.anonymization"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,direction:0
+msgid "Direction"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
+#: view:ir.model.fields.anonymization:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
+msgid "Anonymized Fields"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
+msgid "Database anonymization"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "clear -> anonymized"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Anonymized"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,state:0
+msgid "unknown"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_id:0
+msgid "Object"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,filepath:0
+msgid "File path"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,date:0
+msgid "Date"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_export:0
+msgid "Export"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Reverse the Database Anonymization"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Database Anonymization"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
+msgid "Anonymize database"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,field_ids:0
+msgid "Fields"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Clear"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+#: field:ir.model.fields.anonymize.wizard,summary:0
+msgid "Summary"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization:0
+msgid "Anonymized Field"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Unstable"
+msgstr "Тогтмол биш"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Exception occured"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Not Existing"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_name:0
+msgid "Object Name"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
+#: view:ir.model.fields.anonymization.history:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
+msgid "Anonymization History"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
+msgid "ir.model.fields.anonymization.history"
+msgstr ""
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Anonymize Database"
+msgstr ""
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,name:0
+msgid "File Name"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "anonymized -> clear"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Started"
+msgstr ""
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Done"
+msgstr ""
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,msg:0
+#: field:ir.model.fields.anonymize.wizard,msg:0
+msgid "Message"
+msgstr ""
+
+#. module: anonymization
+#: code:addons/anonymization/anonymization.py:55
+#: sql_constraint:ir.model.fields.anonymization:0
+#, python-format
+msgid "You cannot have two fields with the same name on the same object!"
+msgstr ""
diff --git a/addons/hr/i18n/lt.po b/addons/hr/i18n/lt.po
index 84a46bb3a5d..f50c071b739 100644
--- a/addons/hr/i18n/lt.po
+++ b/addons/hr/i18n/lt.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 01:37+0100\n"
-"PO-Revision-Date: 2012-05-10 18:17+0000\n"
-"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
+"PO-Revision-Date: 2012-10-21 21:20+0000\n"
+"Last-Translator: mchip <mifchip@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-19 05:20+0000\n"
+"X-Launchpad-Export-Date: 2012-10-22 04:40+0000\n"
"X-Generator: Launchpad (build 16165)\n"
#. module: hr
@@ -103,7 +103,7 @@ msgstr ""
#. module: hr
#: model:ir.actions.todo.category,name:hr.category_hr_management_config
msgid "HR Management"
-msgstr ""
+msgstr "Žmogiškųjų išteklių valdymas"
#. module: hr
#: help:hr.employee,partner_id:0
@@ -130,7 +130,7 @@ msgstr "Pastabos"
#. module: hr
#: selection:hr.employee,marital:0
msgid "Married"
-msgstr ""
+msgstr "Vedęs"
#. module: hr
#: model:ir.actions.act_window,help:hr.action_create_hr_employee_installer
@@ -152,7 +152,7 @@ msgstr ""
#. module: hr
#: field:hr.employee,color:0
msgid "Color Index"
-msgstr ""
+msgstr "Spalvos indeksas"
#. module: hr
#: model:process.transition,note:hr.process_transition_employeeuser0
@@ -169,7 +169,7 @@ msgstr ""
#. module: hr
#: field:hr.employee,identification_id:0
msgid "Identification No"
-msgstr ""
+msgstr "Asmens kodas"
#. module: hr
#: selection:hr.employee,gender:0
@@ -206,7 +206,7 @@ msgstr "Žemesniosios kategorijos"
#: view:hr.job:0 field:hr.job,description:0
#: model:ir.model,name:hr.model_hr_job
msgid "Job Description"
-msgstr ""
+msgstr "Darbo aprašymas"
#. module: hr
#: field:hr.employee,work_location:0
diff --git a/addons/hr_attendance/report/attendance_by_month.py b/addons/hr_attendance/report/attendance_by_month.py
index 17cf548345e..fe6d09a6084 100644
--- a/addons/hr_attendance/report/attendance_by_month.py
+++ b/addons/hr_attendance/report/attendance_by_month.py
@@ -86,6 +86,8 @@ class report_custom(report_rml):
for att in attendences:
dt = datetime.strptime(att['name'], '%Y-%m-%d %H:%M:%S')
if ldt and att['action'] == 'sign_out':
+ if dt.date() > ldt.date():
+ dt = ldt
wh += (float((dt - ldt).seconds)/60/60)
else:
ldt = dt
diff --git a/addons/hr_attendance/report/timesheet.py b/addons/hr_attendance/report/timesheet.py
index 900f982dc74..326ffce63e0 100644
--- a/addons/hr_attendance/report/timesheet.py
+++ b/addons/hr_attendance/report/timesheet.py
@@ -38,7 +38,7 @@ class report_custom(report_rml):
def create_xml(self, cr, uid, ids, datas, context=None):
obj_emp = pooler.get_pool(cr.dbname).get('hr.employee')
-
+ ids = datas['active_ids']
start_date = datetime.strptime(datas['form']['init_date'], '%Y-%m-%d')
end_date = datetime.strptime(datas['form']['end_date'], '%Y-%m-%d')
first_monday = start_date - relativedelta(days=start_date.date().weekday())
diff --git a/addons/hr_attendance/wizard/hr_attendance_byweek.py b/addons/hr_attendance/wizard/hr_attendance_byweek.py
index 9ee69a937d1..454ba7764da 100644
--- a/addons/hr_attendance/wizard/hr_attendance_byweek.py
+++ b/addons/hr_attendance/wizard/hr_attendance_byweek.py
@@ -37,6 +37,7 @@ class hr_attendance_byweek(osv.osv_memory):
def print_report(self, cr, uid, ids, context=None):
datas = {
'ids': [],
+ 'active_ids': context['active_ids'],
'model': 'hr.employee',
'form': self.read(cr, uid, ids)[0]
}
diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml
index 288231a4000..330c86652dd 100644
--- a/addons/hr_recruitment/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/hr_recruitment_data.xml
@@ -313,7 +313,7 @@ You can automatically receive job application though an email gateway, see the H
<field eval="0" name="rating_allow_one_column_require"/>
<field name="req_error_msg">This question requires an answer.</field>
<field eval="3" name="sequence"/>
- <field name="question">Exprience</field>
+ <field name="question">Experience</field>
<field eval="0" name="is_require_answer"/>
<field name="type">comment</field>
<field name="comment_valid_err_msg">The comment you entered is in an invalid format.</field>
diff --git a/addons/hr_timesheet/i18n/mk.po b/addons/hr_timesheet/i18n/mk.po
new file mode 100644
index 00000000000..21924603c20
--- /dev/null
+++ b/addons/hr_timesheet/i18n/mk.po
@@ -0,0 +1,642 @@
+# Macedonian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-10-20 13:07+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Macedonian <mk@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-10-21 04:41+0000\n"
+"X-Generator: Launchpad (build 16165)\n"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Wed"
+msgstr "Сре"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "(Keep empty for current_time)"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
+#, python-format
+msgid "No employee defined for your user !"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Group By..."
+msgstr "Групирај По..."
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.action_hr_timesheet_sign_in
+msgid ""
+"Employees can encode their time spent on the different projects. A project "
+"is an analytic account and the time spent on a project generate costs on the "
+"analytic account. This feature allows to record at the same time the "
+"attendance and the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Today"
+msgstr "Денес"
+
+#. module: hr_timesheet
+#: field:hr.employee,journal_id:0
+msgid "Analytic Journal"
+msgstr "Аналитичка картица"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Stop Working"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_employee
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_employee
+msgid "Employee Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Work done stats"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_reporting_timesheet
+msgid "Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Mon"
+msgstr "Пон"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Sign in"
+msgstr "Најава"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Fri"
+msgstr "Пет"
+
+#. module: hr_timesheet
+#: field:hr.employee,uom_id:0
+msgid "UoM"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid ""
+"Employees can encode their time spent on the different projects they are "
+"assigned on. A project is an analytic account and the time spent on a "
+"project generates costs on the analytic account. This feature allows to "
+"record at the same time the attendance and the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,analytic_amount:0
+msgid "Minimum Analytic Amount"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "Monthly Employee Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Work done in the last period"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,state:0
+#: field:hr.sign.out.project,state:0
+msgid "Current state"
+msgstr "Тековен статус"
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,name:0
+#: field:hr.sign.out.project,name:0
+msgid "Employees name"
+msgstr "Име на Вработениот"
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,account_id:0
+msgid "Project / Analytic Account"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_users
+msgid "Print Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:175
+#: code:addons/hr_timesheet/hr_timesheet.py:177
+#, python-format
+msgid "Warning !"
+msgstr "Внимание !"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:132
+#, python-format
+msgid "UserError"
+msgstr "Корисничка Грешка"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py:77
+#, python-format
+msgid "No cost unit defined for this employee !"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Tue"
+msgstr "Вто"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
+#, python-format
+msgid "Warning"
+msgstr "Предупредување"
+
+#. module: hr_timesheet
+#: field:hr.analytic.timesheet,partner_id:0
+msgid "Partner"
+msgstr "Партнер"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+#: view:hr.sign.out.project:0
+msgid "Sign In/Out by Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Sat"
+msgstr "Саб"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Sun"
+msgstr "Нед"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Analytic account"
+msgstr "Аналитичко конто"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+#: view:hr.analytical.timesheet.users:0
+msgid "Print"
+msgstr "Печати"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: model:ir.actions.act_window,name:hr_timesheet.act_hr_timesheet_line_evry1_all_form
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_working_hours
+msgid "Timesheet Lines"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.users:0
+msgid "Monthly Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "July"
+msgstr "Јули"
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,date:0
+#: field:hr.sign.out.project,date_start:0
+msgid "Starting Date"
+msgstr "Почетен датум"
+
+#. module: hr_timesheet
+#: view:hr.employee:0
+msgid "Categories"
+msgstr "Категории"
+
+#. module: hr_timesheet
+#: constraint:hr.analytic.timesheet:0
+msgid "You cannot modify an entry in a Confirmed/Done timesheet !."
+msgstr ""
+
+#. module: hr_timesheet
+#: help:hr.employee,product_id:0
+msgid "Specifies employee's designation as a product with type 'service'."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Total cost"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "September"
+msgstr "Септември"
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytic_timesheet
+msgid "Timesheet Line"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.users,employee_ids:0
+msgid "employees"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Stats by month"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+#: field:hr.analytical.timesheet.employee,month:0
+#: field:hr.analytical.timesheet.users,month:0
+msgid "Month"
+msgstr "Месец"
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,info:0
+msgid "Work Description"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Invoice Analysis"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.report.xml,name:hr_timesheet.report_user_timesheet
+msgid "Employee timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_in
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_sign_out
+msgid "Sign in / Sign out by project"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_define_analytic_structure
+msgid "Define your Analytic Structure"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Sign in / Sign out"
+msgstr "Најава / Одјава"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:175
+#, python-format
+msgid ""
+"Analytic journal is not defined for employee %s \n"
+"Define an employee for the selected user and assign an analytic journal!"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "(Keep empty for current time)"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.employee:0
+msgid "Timesheets"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.action_define_analytic_structure
+msgid ""
+"You should create an analytic account structure depending on your needs to "
+"analyse costs and revenues. In OpenERP, analytic accounts are also used to "
+"track customer contracts."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytic.timesheet,line_id:0
+msgid "Analytic Line"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "August"
+msgstr "Август"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "June"
+msgstr "Јуни"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "Print My Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Date"
+msgstr "Датум"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "November"
+msgstr "Ноември"
+
+#. module: hr_timesheet
+#: constraint:hr.employee:0
+msgid "Error ! You cannot create recursive Hierarchy of Employees."
+msgstr "Грешка! Не можете да креирате рекурзивна хиерархија на вработените."
+
+#. module: hr_timesheet
+#: field:hr.sign.out.project,date:0
+msgid "Closing Date"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "October"
+msgstr "Октомври"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "January"
+msgstr "Јануари"
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Key dates"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:43
+#: code:addons/hr_timesheet/report/users_timesheet.py:77
+#, python-format
+msgid "Thu"
+msgstr "Чет"
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Analysis stats"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_analytical_timesheet_employee
+msgid "Print Employee Timesheet & Print My Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,emp_id:0
+#: field:hr.sign.out.project,emp_id:0
+msgid "Employee ID"
+msgstr "Идентификационен Број на Вработениот"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "General Information"
+msgstr "Општи информации"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_my
+msgid "My Current Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "December"
+msgstr "Декември"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+#: view:hr.analytical.timesheet.users:0
+#: view:hr.sign.in.project:0
+#: view:hr.sign.out.project:0
+msgid "Cancel"
+msgstr "Откажи"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,name:hr_timesheet.action_hr_timesheet_users
+#: model:ir.actions.report.xml,name:hr_timesheet.report_users_timesheet
+#: model:ir.actions.wizard,name:hr_timesheet.wizard_hr_timesheet_users
+#: model:ir.ui.menu,name:hr_timesheet.menu_hr_timesheet_users
+msgid "Employees Timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Information"
+msgstr "Информации"
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.employee,employee_id:0
+#: model:ir.model,name:hr_timesheet.model_hr_employee
+msgid "Employee"
+msgstr "Вработен"
+
+#. module: hr_timesheet
+#: model:ir.actions.act_window,help:hr_timesheet.act_hr_timesheet_line_evry1_all_form
+msgid ""
+"Through this menu you can register and follow your workings hours by project "
+"every day."
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.sign.in.project,server_date:0
+#: field:hr.sign.out.project,server_date:0
+msgid "Current Date"
+msgstr "Тековен датум"
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.employee:0
+msgid "This wizard will print monthly timesheet"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+#: field:hr.employee,product_id:0
+msgid "Product"
+msgstr "Продукт"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Invoicing"
+msgstr "Фактурирање"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "May"
+msgstr "Мај"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Total time"
+msgstr "Вкупно време"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "(local time on the server side)"
+msgstr ""
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_sign_in_project
+msgid "Sign In By Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "February"
+msgstr "Февруари"
+
+#. module: hr_timesheet
+#: model:ir.model,name:hr_timesheet.model_hr_sign_out_project
+msgid "Sign Out By Project"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:hr.analytical.timesheet.users:0
+msgid "Employees"
+msgstr "Вработени"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "March"
+msgstr "Март"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/report/user_timesheet.py:40
+#: code:addons/hr_timesheet/report/users_timesheet.py:73
+#: selection:hr.analytical.timesheet.employee,month:0
+#: selection:hr.analytical.timesheet.users,month:0
+#, python-format
+msgid "April"
+msgstr "Април"
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/hr_timesheet.py:177
+#, python-format
+msgid ""
+"No analytic account defined on the project.\n"
+"Please set one or we can not automatically fill the timesheet."
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+#: view:hr.analytic.timesheet:0
+msgid "Users"
+msgstr "Корисници"
+
+#. module: hr_timesheet
+#: view:hr.sign.in.project:0
+msgid "Start Working"
+msgstr ""
+
+#. module: hr_timesheet
+#: view:account.analytic.account:0
+msgid "Stats by user"
+msgstr ""
+
+#. module: hr_timesheet
+#: code:addons/hr_timesheet/wizard/hr_timesheet_print_employee.py:42
+#, python-format
+msgid "No employee defined for this user"
+msgstr ""
+
+#. module: hr_timesheet
+#: field:hr.analytical.timesheet.employee,year:0
+#: field:hr.analytical.timesheet.users,year:0
+msgid "Year"
+msgstr "Година"
+
+#. module: hr_timesheet
+#: view:hr.analytic.timesheet:0
+msgid "Accounting"
+msgstr "Сметководство"
+
+#. module: hr_timesheet
+#: view:hr.sign.out.project:0
+msgid "Change Work"
+msgstr ""
+
+#~ msgid "Sum"
+#~ msgstr "Вкупно"
+
+#~ msgid "Total"
+#~ msgstr "Вкупно"
diff --git a/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py b/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
index e92e88bdcbd..031a17baee0 100644
--- a/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
+++ b/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
@@ -147,7 +147,7 @@ class hr_si_project(osv.osv_memory):
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'hr.sign.%s.project' % in_out,
- 'views': [(False,'tree'), (resource_id,'form')],
+ 'views': [(resource_id,'form')],
'type': 'ir.actions.act_window',
'target': 'new'
}
diff --git a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
index ab76f2b0f64..30e4ff40885 100644
--- a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
+++ b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
@@ -176,7 +176,7 @@ account_analytic_line()
class hr_analytic_timesheet(osv.osv):
_inherit = "hr.analytic.timesheet"
- def on_change_account_id(self, cr, uid, ids, account_id):
+ def on_change_account_id(self, cr, uid, ids, account_id, user_id=False):
res = {}
if not account_id:
return res
diff --git a/addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml b/addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml
index b752ade8da0..95fa39a6eda 100644
--- a/addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml
+++ b/addons/hr_timesheet_invoice/hr_timesheet_invoice_view.xml
@@ -50,7 +50,7 @@
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
<field name="arch" type="xml">
<field name="account_id" position="replace">
- <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+ <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
</field>
</field>
</record>
@@ -72,7 +72,7 @@
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
<field name="arch" type="xml">
<field name="account_id" position="replace">
- <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+ <field domain="[('type','in',['normal','contract']),('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
</field>
</field>
</record>
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index 96cb15ddce1..e62134ee38a 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -388,7 +388,7 @@ class hr_timesheet_line(osv.osv):
return True
def multi_on_change_account_id(self, cr, uid, ids, account_ids, context=None):
- return dict([(el, self.on_change_account_id(cr, uid, ids, el)) for el in account_ids])
+ return dict([(el, self.on_change_account_id(cr, uid, ids, el, context.get('user_id', uid))) for el in account_ids])
hr_timesheet_line()
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
index b247805d50d..fc35a17377f 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet_view.xml
@@ -97,7 +97,7 @@
<field colspan="4" context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
<tree editable="top" string="Timesheet Lines">
<field name="date"/>
- <field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
+ <field domain="[('type','in',['normal', 'contract']), ('state', '&lt;&gt;', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id)" context="{'default_use_timesheets': 1}"/>
<field name="name"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
<field name="to_invoice" widget="selection"/>
@@ -110,7 +110,7 @@
</tree>
<form string="Timesheet Lines" version="7.0">
<field name="date"/>
- <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id)"/>
+ <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id, user_id)"/>
<field name="name"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
<field name="to_invoice"/>
diff --git a/addons/hr_timesheet_sheet/report/timesheet_report.py b/addons/hr_timesheet_sheet/report/timesheet_report.py
index 497fe8da117..cfd87d784ad 100644
--- a/addons/hr_timesheet_sheet/report/timesheet_report.py
+++ b/addons/hr_timesheet_sheet/report/timesheet_report.py
@@ -46,6 +46,7 @@ class timesheet_report(osv.osv):
'department_id':fields.many2one('hr.department','Department',readonly=True),
'date_from': fields.date('Date from',readonly=True,),
'date_to': fields.date('Date to',readonly=True),
+ 'date_current': fields.date('Current date', required=True),
'state' : fields.selection([
('new', 'New'),
('draft','Draft'),
@@ -64,6 +65,9 @@ class timesheet_report(osv.osv):
htss.name,
htss.date_from,
htss.date_to,
+ to_char(htss.date_from, 'YYYY-MM-DD') as day,
+ to_char(htss.date_from, 'YYYY') as year,
+ to_char(htss.date_from, 'MM') as month,
count(*) as nbr,
aal.unit_amount as quantity,
aal.amount as cost,
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 989b63afee5..f561919939d 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -45,7 +45,7 @@ class mail_message(osv.Model):
_inherit = ['ir.needaction_mixin']
_order = 'id desc'
- _message_read_limit = 10
+ _message_read_limit = 15
_message_read_fields = ['id', 'parent_id', 'model', 'res_id', 'body', 'subject', 'date', 'to_read',
'type', 'vote_user_ids', 'attachment_ids', 'author_id', 'partner_ids', 'record_name', 'favorite_user_ids']
_message_record_name_length = 18
@@ -77,8 +77,7 @@ class mail_message(osv.Model):
notif_obj = self.pool.get('mail.notification')
notif_ids = notif_obj.search(cr, uid, [
('partner_id', 'in', [partner_id]),
- ('message_id', 'in', ids),
- ('read', '=', True)
+ ('message_id', 'in', ids)
], context=context)
for notif in notif_obj.browse(cr, uid, notif_ids, context=context):
res[notif.message_id.id] = not notif.read
@@ -163,13 +162,14 @@ class mail_message(osv.Model):
#------------------------------------------------------
def vote_toggle(self, cr, uid, ids, context=None):
- ''' Toggles vote. Performed using read to avoid access rights issues. '''
+ ''' Toggles vote. Performed using read to avoid access rights issues.
+ Done as SUPERUSER_ID because uid may vote for a message he cannot modify. '''
for message in self.read(cr, uid, ids, ['vote_user_ids'], context=context):
new_has_voted = not (uid in message.get('vote_user_ids'))
if new_has_voted:
- self.write(cr, uid, message.get('id'), {'vote_user_ids': [(4, uid)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(4, uid)]}, context=context)
else:
- self.write(cr, uid, message.get('id'), {'vote_user_ids': [(3, uid)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'vote_user_ids': [(3, uid)]}, context=context)
return new_has_voted or False
#------------------------------------------------------
@@ -177,13 +177,14 @@ class mail_message(osv.Model):
#------------------------------------------------------
def favorite_toggle(self, cr, uid, ids, context=None):
- ''' Toggles favorite. Performed using read to avoid access rights issues. '''
+ ''' Toggles favorite. Performed using read to avoid access rights issues.
+ Done as SUPERUSER_ID because uid may star a message he cannot modify. '''
for message in self.read(cr, uid, ids, ['favorite_user_ids'], context=context):
new_is_favorite = not (uid in message.get('favorite_user_ids'))
if new_is_favorite:
- self.write(cr, uid, message.get('id'), {'favorite_user_ids': [(4, uid)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(4, uid)]}, context=context)
else:
- self.write(cr, uid, message.get('id'), {'favorite_user_ids': [(3, uid)]}, context=context)
+ self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(3, uid)]}, context=context)
return new_is_favorite or False
#------------------------------------------------------
@@ -252,9 +253,11 @@ class mail_message(osv.Model):
# result = sorted(result, key=lambda k: k['id'])
tree_not = []
# expandable for not show message
- for message_id, message in read_messages.iteritems():
- # get all childs
- # SHOULD NOT BE SUPERUSED_ID -> check search is correctly implemented in mail.message
+ id_list = sorted(read_messages.keys())
+ for message_id in id_list:
+ message = read_messages[message_id]
+
+ # TDE note: check search is correctly implemented in mail.message
not_loaded_ids = self.search(cr, uid, [
('parent_id', '=', message['id']),
('id', 'not in', message_loaded_ids),
@@ -307,7 +310,7 @@ class mail_message(osv.Model):
'type': 'expandable',
'parent_id': parent_id,
'id': -1,
- 'max_limit': True
+ 'max_limit': True,
})
return message_list
@@ -342,11 +345,9 @@ class mail_message(osv.Model):
further parents
:return list: list of trees of messages
"""
- print '>>> executing message_read'
if message_loaded_ids:
domain += [('id', 'not in', message_loaded_ids)]
limit = limit or self._message_read_limit
- limit = 200
read_messages = {}
message_list = []
@@ -359,37 +360,36 @@ class mail_message(osv.Model):
# TDE FIXME: check access rights on search are implemented for mail.message
# fetch messages according to the domain, add their parents if uid has access to
- if not ids:
- ids = self.search(cr, uid, domain, context=context, limit=limit)
- for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
- # if not in tree and not in message_loded list
- if not read_messages.get(message.get('id')) and message.get('id') not in message_loaded_ids:
- read_messages[message.get('id')] = message
- message_list.append(self._message_get_dict(cr, uid, message, context=context))
-
- # get all parented message if the user have the access
- parent = self._get_parent(cr, uid, message, context=context)
- while parent and parent.get('id') != parent_id:
- if not read_messages.get(parent.get('id')) and parent.get('id') not in message_loaded_ids:
- read_messages[parent.get('id')] = parent
- message_list.append(self._message_get_dict(cr, uid, parent, context=context))
- parent = self._get_parent(cr, uid, parent, context=context)
-
- # get the child expandable messages for the tree
- message_list = sorted(message_list, key=lambda k: k['id'])
- message_list = self._message_read_expandable(cr, uid, message_list, read_messages,
- message_loaded_ids=message_loaded_ids, domain=domain, context=context, parent_id=parent_id, limit=limit)
+ ids = self.search(cr, uid, domain, context=context, limit=limit)
+ for message in self.read(cr, uid, ids, self._message_read_fields, context=context):
+ # if not in tree and not in message_loded list
+ if not read_messages.get(message.get('id')) and message.get('id') not in message_loaded_ids:
+ read_messages[message.get('id')] = message
+ message_list.append(self._message_get_dict(cr, uid, message, context=context))
+
+ # get all parented message if the user have the access
+ parent = self._get_parent(cr, uid, message, context=context)
+ while parent and parent.get('id') != parent_id:
+ if not read_messages.get(parent.get('id')) and parent.get('id') not in message_loaded_ids:
+ read_messages[parent.get('id')] = parent
+ message_list.append(self._message_get_dict(cr, uid, parent, context=context))
+ parent = self._get_parent(cr, uid, parent, context=context)
+
+ # get the child expandable messages for the tree
+ message_list = sorted(message_list, key=lambda k: k['id'])
+ message_list = self._message_read_expandable(cr, uid, message_list, read_messages,
+ message_loaded_ids=message_loaded_ids, domain=domain, context=context, parent_id=parent_id, limit=limit)
return message_list
# TDE Note: do we need this ?
- def user_free_attachment(self, cr, uid, context=None):
- attachment = self.pool.get('ir.attachment')
- attachment_list = []
- attachment_ids = attachment.search(cr, uid, [('res_model', '=', 'mail.message'), ('create_uid', '=', uid)])
- if len(attachment_ids):
- attachment_list = [{'id': attach.id, 'name': attach.name, 'date': attach.create_date} for attach in attachment.browse(cr, uid, attachment_ids, context=context)]
- return attachment_list
+ # def user_free_attachment(self, cr, uid, context=None):
+ # attachment = self.pool.get('ir.attachment')
+ # attachment_list = []
+ # attachment_ids = attachment.search(cr, uid, [('res_model', '=', 'mail.message'), ('create_uid', '=', uid)])
+ # if len(attachment_ids):
+ # attachment_list = [{'id': attach.id, 'name': attach.name, 'date': attach.create_date} for attach in attachment.browse(cr, uid, attachment_ids, context=context)]
+ # return attachment_list
#------------------------------------------------------
# Email api
@@ -410,7 +410,7 @@ class mail_message(osv.Model):
- create: if
- I am in the document message_follower_ids OR
- I can write on the related document if res_model, res_id OR
- - I write a mail to another user (no res_model)
+ - I create a private message (no model, no res_id)
- Otherwise: raise
- write: if
- I can write on the related document if res_model, res_id
@@ -448,10 +448,14 @@ class mail_message(osv.Model):
if operation == 'read':
author_ids = [mid for mid, message in message_values.iteritems()
if message.get('author_id') and message.get('author_id') == partner_id]
+ # Create: Check messages you create that are private messages -> ir.rule ?
+ elif operation == 'create':
+ author_ids = [mid for mid, message in message_values.iteritems()
+ if not message.get('model') and not message.get('res_id')]
else:
author_ids = []
- # Create: Check message_follower_ids and author_ids
+ # Create: Check message_follower_ids
if operation == 'create':
doc_follower_ids = []
for model, mids in model_record_ids.items():
@@ -467,12 +471,6 @@ class mail_message(osv.Model):
else:
doc_follower_ids = []
- # Create/write: Check author_ids
- if operation == 'create' or operation == 'write':
- author_ids = author_ids+[mid for mid, message in message_values.iteritems()
- if message.get('author_id') and message.get('author_id') == partner_id and not message.get('res_model')]
-
-
# Calculate remaining ids, and related model/res_ids
model_record_ids = {}
other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids))
diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml
index fbdfbc27125..4677beee511 100644
--- a/addons/mail/mail_message_view.xml
+++ b/addons/mail/mail_message_view.xml
@@ -58,7 +58,7 @@
<field name="author_id"/>
<field name="partner_ids"/>
<filter string="Unread"
- name="messages_unread" help="Show messages to read"
+ name="message_unread" help="Show messages to read"
domain="[('to_read', '=', True)]"/>
<filter string="Comments"
name="comments" help="Comments"
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index c846f8f3483..04da686b49d 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -108,12 +108,12 @@ class mail_thread(osv.AbstractModel):
# find the document followers, update the data
fol_obj = self.pool.get('mail.followers')
- fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
+ 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, SUPERUSER_ID, fol_ids, context=context):
+ for fol in fol_obj.browse(cr, uid, fol_ids, context=context):
thread_subtype_dict = res[fol.res_id]['message_subtype_data']
for subtype in fol.subtype_ids:
thread_subtype_dict[subtype.name]['followed'] = True
@@ -225,8 +225,8 @@ class mail_thread(osv.AbstractModel):
def create(self, cr, uid, vals, context=None):
""" Override to subscribe the current user. """
- thread_id = super(mail_thread, self).create(cr, SUPERUSER_ID, vals, context=context)
- self.message_subscribe_users(cr, SUPERUSER_ID, [thread_id], [uid], context=context)
+ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context)
+ self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context)
return thread_id
def unlink(self, cr, uid, ids, context=None):
@@ -705,10 +705,10 @@ class mail_thread(osv.AbstractModel):
mail_message = self.pool.get('mail.message')
attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', 'mail.message'), ('res_id', '=', 0), ('create_uid', '=', uid), ('id', 'in', attachments)], context=context)
if attachment_ids:
- ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, { 'res_model': self._name, 'res_id': thread_id }, context=context)
- mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]} )
-
- new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id])
+ ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context)
+ mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context)
+
+ new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id], context=context)
return new_message
#------------------------------------------------------
diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py
index c318538541f..54b8a76703f 100644
--- a/addons/mail/res_users.py
+++ b/addons/mail/res_users.py
@@ -126,6 +126,19 @@ class res_users(osv.Model):
return self.pool.get('res.partner').message_post_api(cr, uid, partner_id, body=body, subject=subject,
type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs)
+ def message_post(self, cr, uid, thread_id, context=None, **kwargs):
+ """ Redirect the posting of message on res.users to the related partner.
+ This is done because when giving the context of Chatter on the
+ various mailboxes, we do not have access to the current partner_id.
+ We therefore post on the user and redirect on its partner. """
+ assert thread_id, "res.users does not support posting global messages"
+ if context and 'thread_model' in context:
+ context['thread_model'] = 'res.partner'
+ if isinstance(thread_id, (list, tuple)):
+ thread_id = thread_id[0]
+ partner_id = self.pool.get('res.users').read(cr, uid, thread_id, ['partner_id'], context=context)['partner_id'][0]
+ return self.pool.get('res.partner').message_post(cr, uid, partner_id, context=context, **kwargs)
+
def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
partner_id = self.pool.get('res.users').browse(cr, uid, ids)[0].partner_id.id
return self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict,
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml
index 53083a51d5a..3f2b7bf3e9a 100644
--- a/addons/mail/security/mail_security.xml
+++ b/addons/mail/security/mail_security.xml
@@ -11,7 +11,7 @@
</record>
<record id="mail_followers_read_own" model="ir.rule">
- <field name="name">mail.followers: read its own entries</field>
+ <field name="name">mail.followers: read and write its own entries</field>
<field name="model_id" ref="model_mail_followers"/>
<field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
<field name="perm_create" eval="False"/>
diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css
index 22054686145..9dd18b0fec5 100644
--- a/addons/mail/static/src/css/mail.css
+++ b/addons/mail/static/src/css/mail.css
@@ -63,6 +63,9 @@
opacity: 0.8;
-webkit-transition: opacity 0.2s linear;
}
+.openerp .oe_mail .oe_msg.oe_msg_composer .oe_msg_footer{
+ height: auto;
+}
.openerp .oe_mail .oe_msg .oe_msg_content{
display: block;
overflow: hidden;
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index e49811ab38c..58f1f82325e 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -7,7 +7,7 @@ openerp.mail = function(session) {
openerp_mail_followers(session, mail); // import mail_followers.js
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* FormView
* ------------------------------------------------------------
*
@@ -23,7 +23,7 @@ openerp.mail = function(session) {
*/
var context_keys = ['default_template_id', 'default_composition_mode',
'default_use_template', 'default_partner_ids', 'default_model',
- 'default_res_id', 'default_subtype', 'active_id', 'lang',
+ 'default_res_id', 'default_content_subtype', 'active_id', 'lang',
'bin_raw', 'tz', 'active_model', 'edi_web_url_view', 'active_ids']
for (var key in action.context) {
if (_.indexOf(context_keys, key) == -1) {
@@ -38,7 +38,7 @@ openerp.mail = function(session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* ChatterUtils
* ------------------------------------------------------------
*
@@ -51,17 +51,20 @@ openerp.mail = function(session) {
mail.ChatterUtils = {
- /** Get an image in /web/binary/image?... */
+ /**
+ *Get an image in /web/binary/image?... */
get_image: function(session, model, field, id) {
return session.prefix + '/web/binary/image?session_id=' + session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || '');
},
- /** Get the url of an attachment {'id': id} */
+ /**
+ *Get the url of an attachment {'id': id} */
get_attachment_url: function (session, attachment) {
return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id'];
},
- /** Replaces some expressions
+ /**
+ *Replaces some expressions
* - :name - shortcut to an image
*/
do_replace_expressions: function (string) {
@@ -91,7 +94,7 @@ openerp.mail = function(session) {
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* ComposeMessage widget
* ------------------------------------------------------------
*
@@ -118,21 +121,16 @@ openerp.mail = function(session) {
var self = this;
this._super(parent);
this.context = options.context || {};
-
- this.datasets = {
- 'attachment_ids' : [],
- 'id': datasets.id,
- 'model': datasets.model,
- 'show_compact': true,
- 'res_model': datasets.res_model,
- 'is_private': datasets.is_private || false,
- 'partner_ids': datasets.partner_ids || [],
- 'avatar': mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid),
- };
- this.options={};
- this.options.display_indented_thread = options.options.display_indented_thread || -1;
- this.options.show_attachment_delete = true;
-
+ this.options = options.options;
+
+ // data of this compose message
+ this.attachment_ids = [];
+ this.id = datasets.id;
+ this.model = datasets.model;
+ this.res_model = datasets.res_model;
+ this.is_private = datasets.is_private || false;
+ this.partner_ids = datasets.partner_ids || [];
+ this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
this.parent_thread= parent.messages!= undefined ? parent : false;
this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
@@ -147,12 +145,6 @@ openerp.mail = function(session) {
start: function(){
this.$render_compact = this.$el;
- if(this.datasets.show_compact) {
- this.$render_compact.show();
- } else {
- this.$render_compact.hide();
- }
-
this.bind_events();
},
@@ -162,14 +154,14 @@ openerp.mail = function(session) {
var self = this;
var render = $(session.web.qweb.render('mail.thread.message.attachments', {'widget': self}));
if(!this.list_attachment){
- this.$('.oe_msg_attachment_list').replaceWith( render );
+ this.$render_expandable.find('.oe_msg_attachment_list').replaceWith( render );
} else {
this.list_attachment.replaceWith( render );
}
- this.list_attachment = this.$(".oe_msg_attachments");
+ this.list_attachment = this.$render_expandable.find(".oe_msg_attachments");
// event: delete an attachment
- this.$el.on('click', '.oe_mail_attachment_delete', self.on_attachment_delete);
+ this.$render_expandable.on('click', '.oe_mail_attachment_delete', self.on_attachment_delete);
},
/* when a user click on the upload button, send file read on_attachment_loaded
@@ -184,25 +176,24 @@ openerp.mail = function(session) {
// if the files exits for this answer, delete the file before upload
var attachments=[];
- for(var i in this.datasets.attachment_ids){
- if((this.datasets.attachment_ids[i].filename || this.datasets.attachment_ids[i].name) == filename){
- if(this.datasets.attachment_ids[i].upload){
+ for(var i in this.attachment_ids){
+ if((this.attachment_ids[i].filename || this.attachment_ids[i].name) == filename){
+ if(this.attachment_ids[i].upload){
return false;
}
- this.ds_attachment.unlink([this.datasets.attachment_ids[i].id]);
+ this.ds_attachment.unlink([this.attachment_ids[i].id]);
} else {
- attachments.push(this.datasets.attachment_ids[i]);
+ attachments.push(this.attachment_ids[i]);
}
}
- this.datasets.attachment_ids = attachments;
+ this.attachment_ids = attachments;
// submit file
- //session.web.blockUI();
- self.$('form.oe_form_binary_form').submit();
+ this.$render_expandable.find('form.oe_form_binary_form').submit();
- this.$(".oe_attachment_file").hide();
+ this.$render_expandable.find(".oe_attachment_file").hide();
- this.datasets.attachment_ids.push({
+ this.attachment_ids.push({
'id': 0,
'name': filename,
'filename': filename,
@@ -216,10 +207,9 @@ openerp.mail = function(session) {
/* when the file is uploaded
*/
on_attachment_loaded: function (event, result) {
- //session.web.unblockUI();
- for(var i in this.datasets.attachment_ids){
- if(this.datasets.attachment_ids[i].filename == result.filename && this.datasets.attachment_ids[i].upload) {
- this.datasets.attachment_ids[i]={
+ for(var i in this.attachment_ids){
+ if(this.attachment_ids[i].filename == result.filename && this.attachment_ids[i].upload) {
+ this.attachment_ids[i]={
'id': result.id,
'name': result.name,
'filename': result.filename,
@@ -229,9 +219,9 @@ openerp.mail = function(session) {
}
this.display_attachments();
- var $input = this.$('input.oe_form_binary_file');
+ var $input = this.$render_expandable.find('input.oe_form_binary_file');
$input.after($input.clone(true)).remove();
- this.$(".oe_attachment_file").show();
+ this.$render_expandable.find(".oe_attachment_file").show();
},
/* unlink the file on the server and reload display
@@ -241,15 +231,15 @@ openerp.mail = function(session) {
var attachment_id=$(event.target).data("id");
if (attachment_id) {
var attachments=[];
- for(var i in this.datasets.attachment_ids){
- if(attachment_id!=this.datasets.attachment_ids[i].id){
- attachments.push(this.datasets.attachment_ids[i]);
+ for(var i in this.attachment_ids){
+ if(attachment_id!=this.attachment_ids[i].id){
+ attachments.push(this.attachment_ids[i]);
}
else {
this.ds_attachment.unlink([attachment_id]);
}
}
- this.datasets.attachment_ids = attachments;
+ this.attachment_ids = attachments;
this.display_attachments();
}
},
@@ -277,25 +267,38 @@ openerp.mail = function(session) {
bind_events: function() {
var self = this;
- // set the function called when attachments are added
- this.$el.on('change', 'input.oe_form_binary_file', self.on_attachment_change );
- this.$el.on('click', 'a.oe_cancel', self.on_cancel );
- this.$el.on('click', 'button.oe_post', function(){self.on_message_post()} );
- this.$el.on('click', 'button.oe_full', function(){self.on_compose_fullmail()} );
+ this.$render_compact.find('textarea').unbind().on('focus', self.on_compose_expandable);
+
+ if(this.$render_expandable){
+ // set the function called when attachments are added
+ this.$render_expandable.on('change', 'input.oe_form_binary_file', self.on_attachment_change );
+
+ this.$render_expandable.on('click', 'a.oe_cancel', self.on_cancel );
+ this.$render_expandable.on('click', 'button.oe_post', function(){self.on_message_post()} );
+ this.$render_expandable.on('click', 'button.oe_full', function(){self.on_compose_fullmail()} );
- this.$('textarea.oe_compact').on('focus', self.on_compose_expandable);
+ // auto close
+ this.$render_expandable.on('blur', 'textarea', this.on_compose_expandable);
+
+ /* stack for don't close the compose form if the user click on a button */
+ this.$render_expandable.on('focus', 'textarea', function () { self.stay_open = false; });
+ this.$render_expandable.on('mousedown', function () { self.stay_open = true; });
+ }
},
on_compose_fullmail: function(){
var attachments=[];
- for(var i in this.datasets.attachment_ids){
- attachments.push(this.datasets.attachment_ids[i].id);
+ for(var i in this.attachment_ids){
+ attachments.push(this.attachment_ids[i].id);
}
+ /* TDE note: I think this is not necessary, because
+ * 1/ post on a document: followers added server-side in _notify
+ * 2/ reply to a message: mail.compose.message should add the previous partners
+ */
var partner_ids=[];
- for(var i in this.datasets.partner_ids){
- partner_ids.push(this.datasets.partner_ids[i][0]);
+ for(var i in this.partner_ids){
+ partner_ids.push(this.partner_ids[i][0]);
}
-
var action = {
type: 'ir.actions.act_window',
res_model: 'mail.compose.message',
@@ -305,11 +308,11 @@ openerp.mail = function(session) {
views: [[false, 'form']],
target: 'new',
context: {
- 'default_model': false,
- 'default_res_id': 0,
+ 'default_model': this.context.default_model,
+ 'default_res_id': this.context.default_res_id,
'default_content_subtype': 'html',
- 'default_parent_id': this.datasets.id,
- 'default_body': mail.ChatterUtils.get_text2html(this.$('textarea').val() || ''),
+ 'default_parent_id': this.id,
+ 'default_body': mail.ChatterUtils.get_text2html(this.$render_expandable ? (this.$render_expandable.find('textarea').val() || '') : ''),
'default_attachment_ids': attachments,
'default_partner_ids': partner_ids
},
@@ -319,11 +322,14 @@ openerp.mail = function(session) {
on_cancel: function(event){
if(event) event.stopPropagation();
- this.$('textarea').val("");
- this.$('input[data-id]').remove();
- //this.attachment_ids=[];
+ this.$render_expandable.find('textarea').val("");
+ this.$render_expandable.find('input[data-id]').remove();
+
+ this.attachment_ids=[];
this.display_attachments();
- this.$el.hide();
+
+ this.stay_open = false;
+ this.on_compose_expandable();
},
/*post a message and fetch the message*/
@@ -331,21 +337,22 @@ openerp.mail = function(session) {
var self = this;
if (! body) {
- var comment_node = this.$('textarea');
+ var comment_node = this.$render_expandable.find('textarea');
var body = comment_node.val();
comment_node.val('');
}
var attachments=[];
- for(var i in this.datasets.attachment_ids){
- if(this.datasets.attachment_ids[i].upload){
+ for(var i in this.attachment_ids){
+ if(this.attachment_ids[i].upload){
session.web.dialog($('<div>' + session.web.qweb.render('CrashManager.warning', {message: 'Please, wait while the file is uploading.'}) + '</div>'));
return false;
}
- attachments.push(this.datasets.attachment_ids[i].id);
+ attachments.push(this.attachment_ids[i].id);
}
if(body.match(/\S+/)) {
+ //session.web.blockUI();
this.parent_thread.ds_thread.call('message_post_api', [
this.context.default_res_id,
mail.ChatterUtils.get_text2html(body),
@@ -357,8 +364,8 @@ openerp.mail = function(session) {
this.parent_thread.context
]).then(function(records){
self.parent_thread.switch_new_message(records);
- self.datasets.attachment_ids=[];
self.on_cancel();
+ //session.web.unblockUI();
});
return true;
}
@@ -377,13 +384,10 @@ openerp.mail = function(session) {
this.$render_expandable.insertAfter( this.$render_compact );
this.display_attachments();
-
- this.$render_expandable.on('blur', 'textarea', this.on_compose_expandable);
- /* stack for don't close the compose form if the user click on a button */
- this.$render_expandable.on('focus', 'textarea', function () { self.stay_open = false; });
- this.$render_expandable.on('mousedown', function () { self.stay_open = true; });
+ this.bind_events();
}
+
if(this.$render_expandable.is(':hidden')){
this.$render_expandable.show();
@@ -392,11 +396,14 @@ openerp.mail = function(session) {
} else if(!this.stay_open){
- this.$render_expandable.hide();
- if(this.datasets.show_compact) {
- this.$render_compact.show();
- } else {
- this.$render_compact.hide();
+ // do not close the box if there are some text
+ if(!this.$render_expandable.find('textarea').val().match(/\S+/)){
+ this.$render_expandable.hide();
+ if(this.options.show_compact_message) {
+ this.$render_compact.show();
+ } else {
+ this.$render_compact.hide();
+ }
}
}
@@ -405,17 +412,19 @@ openerp.mail = function(session) {
do_hide_compact: function() {
this.$render_compact.hide();
- this.datasets.show_compact = false;
+ this.options.show_compact_message = false;
},
do_show_compact: function() {
- this.$render_compact.show();
- this.datasets.show_compact = true;
+ if(!this.$render_expandable || this.$render_expandable.is(':hidden')){
+ this.$render_compact.show();
+ }
+ this.options.show_compact_message = true;
}
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* Thread Message Expandable Widget
* ------------------------------------------------------------
*
@@ -438,17 +447,15 @@ openerp.mail = function(session) {
default_res_id: 0,
default_parent_id: false }, options.context || {});
- this.datasets = {
- 'id' : datasets.id || -1,
- 'model' : datasets.model || false,
- 'parent_id' : datasets.parent_id || false,
- 'nb_messages' : datasets.nb_messages || 0,
- 'type' : 'expandable',
- 'max_limit' : datasets.max_limit || false,
- 'flag_used' : false,
- };
-
- // record options and data
+ // data of this expandable message
+ this.id = datasets.id || -1,
+ this.model = datasets.model || false,
+ this.parent_id = datasets.parent_id || false,
+ this.nb_messages = datasets.nb_messages || 0,
+ this.thread_level = datasets.thread_level || 0,
+ this.type = 'expandable',
+ this.max_limit = datasets.max_limit || false,
+ this.flag_used = false,
this.parent_thread= parent.messages!= undefined ? parent : options.options._parents[0] ;
},
@@ -483,19 +490,19 @@ openerp.mail = function(session) {
*/
on_expandable: function (event) {
if(event)event.stopPropagation();
- if(this.datasets.flag_used) {
+ if(this.flag_used) {
return false
}
- this.datasets.flag_used = true;
+ this.flag_used = true;
this.animated_destroy({'fadeTime':300});
- this.parent_thread.message_fetch(false, this.domain, this.context);
+ this.parent_thread.message_fetch(this.domain, this.context);
return false;
},
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* Thread Message Widget
* ------------------------------------------------------------
* This widget handles the display of a messages in a thread.
@@ -524,9 +531,6 @@ openerp.mail = function(session) {
* @param {Object} [options]
* @param {Object} [thread] read obout mail.Thread object
* @param {Object} [message]
- * @param {Number} [message_ids=null] ids for message_fetch
- * @param {Number} [message_data=null] already formatted message data,
- * for subthreads getting data from their parent
* @param {Number} [truncate_limit=250] number of character to
* display before having a "show more" link; note that the text
* will not be truncated if it does not have 110% of the parameter
@@ -537,28 +541,26 @@ openerp.mail = function(session) {
init: function(parent, datasets, options) {
this._super(parent);
- // record datasets
- this.datasets = _.extend({
- 'id' : -1,
- 'model' : false,
- 'parent_id': false,
- 'res_id' : false,
- 'type' : false,
- 'is_author' : false,
- 'is_private' : false,
- 'subject' : false,
- 'name' : false,
- 'record_name' : false,
- 'body' : false,
- 'vote_nb' :0,
- 'has_voted' : false,
- 'is_favorite' : false,
- 'thread_level' : 0,
- 'to_read' : true,
- 'author_id' : [],
- 'attachment_ids' : [],
- }, datasets || {});
- this.datasets._date = datasets.date;
+ // data of this message
+ this.id = datasets.id || -1,
+ this.model = datasets.model || false,
+ this.parent_id = datasets.parent_id || false,
+ this.res_id = datasets.res_id || false,
+ this.type = datasets.type || false,
+ this.is_author = datasets.is_author || false,
+ this.is_private = datasets.is_private || false,
+ this.subject = datasets.subject || false,
+ this.name = datasets.name || false,
+ this.record_name = datasets.record_name || false,
+ this.body = datasets.body || false,
+ this.vote_nb = datasets.vote_nb || 0,
+ this.has_voted = datasets.has_voted || false,
+ this.is_favorite = datasets.is_favorite || false,
+ this.thread_level = datasets.thread_level || 0,
+ this.to_read = datasets.to_read || false,
+ this.author_id = datasets.author_id || [],
+ this.attachment_ids = datasets.attachment_ids || [],
+ this._date = datasets.date;
// record domain and context
this.domain = options.domain || [];
@@ -568,23 +570,16 @@ openerp.mail = function(session) {
default_parent_id: false }, options.context || {});
// record options
- this.options = _.extend(options.options, {
- 'message_ids': options.options.message_ids || null,
- 'message_data': options.options.message_data || null,
- 'show_record_name': options.options.show_record_name != undefined ? options.options.show_record_name: true,
- 'truncate_limit': options.options.truncate_limit || 250,
- 'show_reply_button': options.options.show_reply_button || -1,
- 'show_read_unread_button': options.options.show_read_unread_button || -1
- });
+ this.options = options.options;
- this.datasets.show_reply_button = this.options.show_reply_button>this.datasets.thread_level;
- this.datasets.show_read_unread_button = this.options.show_read_unread_button>this.datasets.thread_level;
+ this.show_reply_button = this.options.show_compose_message && this.options.show_reply_button > this.thread_level;
+ this.show_read_unread_button = this.options.show_read_unread_button > this.thread_level;
// record options and data
this.parent_thread= parent.messages!= undefined ? parent : options.options._parents[0];
this.thread = false;
- if( this.datasets.id > 0 ) {
+ if( this.id > 0 ) {
this.formating_data();
}
@@ -593,18 +588,21 @@ openerp.mail = function(session) {
this.ds_follow = new session.web.DataSetSearch(this, 'mail.followers');
},
+ /**
+ *Convert date, timerelative and avatar in displayable data.
+ */
formating_data: function(){
//formating and add some fields for render
- this.datasets.date = session.web.format_value(this.datasets._date, {type:"datetime"});
- this.datasets.timerelative = $.timeago(this.datasets.date);
- if (this.datasets.type == 'email') {
- this.datasets.avatar = ('/mail/static/src/img/email_icon.png');
+ this.date = session.web.format_value(this._date, {type:"datetime"});
+ this.timerelative = $.timeago(this.date);
+ if (this.type == 'email') {
+ this.avatar = ('/mail/static/src/img/email_icon.png');
} else {
- this.datasets.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.datasets.author_id[0]);
+ this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
}
- for (var l in this.datasets.attachment_ids) {
- var attach = this.datasets.attachment_ids[l];
+ for (var l in this.attachment_ids) {
+ var attach = this.attachment_ids[l];
attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
}
},
@@ -628,20 +626,23 @@ openerp.mail = function(session) {
self.$('.oe_msg_attachments:first').toggle();
});
// event: click on icone 'Read' in header
- this.$el.on('click', 'a.oe_read', this.on_message_read_unread);
+ this.$el.on('click', '.oe_read', this.on_message_read_unread);
// event: click on icone 'UnRead' in header
- this.$el.on('click', 'a.oe_unread', this.on_message_read_unread);
+ this.$el.on('click', '.oe_unread', this.on_message_read_unread);
// event: click on 'Delete' in msg side menu
- this.$el.on('click', 'a.oe_msg_delete', this.on_message_delete);
+ this.$el.on('click', '.oe_msg_delete', this.on_message_delete);
// event: click on 'Reply' in msg
- this.$el.on('click', 'a.oe_reply', this.on_message_reply);
+ this.$el.on('click', '.oe_reply', this.on_message_reply);
// event: click on 'Vote' button
- this.$el.on('click', 'button.oe_msg_vote', this.on_vote);
+ this.$el.on('click', '.oe_msg_vote', this.on_vote);
// event: click on 'starred/favorite' button
- this.$el.on('click', 'a.oe_mail_starbox', this.on_star);
+ this.$el.on('click', '.oe_mail_starbox', this.on_star);
},
+ /**
+ * call the on_compose_message on the thread of this message.
+ */
on_message_reply:function(event){
event.stopPropagation();
this.thread.on_compose_message();
@@ -659,27 +660,33 @@ openerp.mail = function(session) {
});
},
+ /**
+ * instantiate the thread object of this message.
+ * Each message have only one thread.
+ */
create_thread: function(){
- var self=this;
if(this.thread){
return false;
}
-
/*create thread*/
- self.thread = new mail.Thread(self, self.datasets, {
- 'domain': self.domain,
+ this.thread = new mail.Thread(this, this, {
+ 'domain': this.domain,
'context':{
- 'default_model': self.datasets.model,
- 'default_res_id': self.datasets.res_id,
- 'default_parent_id': self.datasets.id
+ 'default_model': this.model,
+ 'default_res_id': this.res_id,
+ 'default_parent_id': this.id
},
- 'options': self.options
+ 'options': this.options
}
);
/*insert thread in parent message*/
- self.thread.insertAfter(self.$el);
+ this.thread.insertAfter(this.$el);
},
+ /**
+ * Fade out the message and his child thread.
+ * Then this object is destroyed.
+ */
animated_destroy: function(options) {
var self=this;
//graphic effects
@@ -687,20 +694,24 @@ openerp.mail = function(session) {
self.$el.fadeOut(options.fadeTime, function(){
self.destroy();
});
+ self.thread.$el.fadeOut(options.fadeTime);
} else {
self.destroy();
}
},
+ /**
+ * Wait a confirmation for delete the message on the DB.
+ * Make an animate destroy
+ */
on_message_delete: function (event) {
event.stopPropagation();
if (! confirm(_t("Do you really want to delete this message?"))) { return false; }
this.animated_destroy({fadeTime:250});
// delete this message and his childs
- var ids = [this.datasets.id].concat( this.get_child_ids() );
+ var ids = [this.id].concat( this.get_child_ids() );
this.ds_message.unlink(ids);
- this.animated_destroy();
return false;
},
@@ -708,9 +719,11 @@ openerp.mail = function(session) {
* @param {object} mouse envent
*/
on_message_read_unread: function (event) {
+ // TDE note: code here seems complicated... just check that current message is read (value coming from server)
+ // and send its opposite to set_message_read
event.stopPropagation();
// if this message is read, all childs message display is read
- var ids = [this.datasets.id].concat( this.get_child_ids() );
+ var ids = [this.id].concat( this.get_child_ids() );
var read = $(event.srcElement).hasClass("oe_read");
this.$el.removeClass(read ? 'oe_msg_unread':'oe_msg_read').addClass(read ? 'oe_msg_read':'oe_msg_unread');
@@ -718,12 +731,14 @@ openerp.mail = function(session) {
(!read && this.options.typeof_thread == 'archives')) {
this.animated_destroy({fadeTime:250});
}
-
+ // TDE note: should have a context here
this.ds_notification.call('set_message_read', [ids, read]);
return false;
},
- /** browse message
+ /**
+ * search a message in all thread and child thread.
+ * This method return an object message.
* @param {object}{int} option.id
* @param {object}{string} option.model
* @param {object}{boolean} option._go_thread_wall
@@ -740,7 +755,7 @@ openerp.mail = function(session) {
}
}
- if(this.datasets.id==options.id)
+ if(this.id==options.id)
return this;
for(var i in this.thread.messages){
@@ -753,30 +768,36 @@ openerp.mail = function(session) {
return false;
},
- /* get all child message/thread id linked
+ /* get all child message id linked.
+ * @return array of id
*/
get_child_ids: function(){
var res=[]
- if(arguments[0]) res.push(this.datasets.id);
+ if(arguments[0]) res.push(this.id);
if(this.thread){
res = res.concat( this.thread.get_child_ids(true) );
}
return res;
},
+ /**
+ * add or remove a vote for a message and display the result
+ */
on_vote: function (event) {
event.stopPropagation();
var self=this;
- return this.ds_message.call('vote_toggle', [[self.datasets.id]]).pipe(function(vote){
-
- self.datasets.has_voted=vote;
- self.datasets.vote_nb += self.datasets.has_voted ? 1 : -1;
+ return this.ds_message.call('vote_toggle', [[self.id]]).pipe(function(vote){
+ // TDE note: to update, because vote_user_ids is about to disappear to be replaced by vote_nb (number of votes)
+ self.has_voted=vote;
+ self.vote_nb += self.has_voted ? 1 : -1;
self.display_vote();
});
return false;
},
- // Render vote Display template.
+ /**
+ * Display the render of this message's vote
+ */
display_vote: function () {
var self = this;
var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': self});
@@ -784,14 +805,16 @@ openerp.mail = function(session) {
self.$(".oe_mail_vote_count:first").replaceWith(vote_element);
},
- // Stared/unstared + Render star.
+ /**
+ * add or remove a favorite (or starred) for a message and change class on the DOM
+ */
on_star: function (event) {
event.stopPropagation();
var self=this;
var button = self.$('button.oe_mail_starbox:first');
- return this.ds_message.call('favorite_toggle', [[self.datasets.id]]).pipe(function(star){
- self.datasets.is_favorite=star;
- if(self.datasets.is_favorite){
+ return this.ds_message.call('favorite_toggle', [[self.id]]).pipe(function(star){
+ self.is_favorite=star;
+ if(self.is_favorite){
button.addClass('oe_stared');
} else {
button.removeClass('oe_stared');
@@ -805,8 +828,8 @@ openerp.mail = function(session) {
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* Thread Widget
* ------------------------------------------------------------
*
@@ -831,10 +854,6 @@ openerp.mail = function(session) {
* @param {Object} [options]
* @param {Object} [message] read about mail.ThreadMessage object
* @param {Object} [thread]
- * @param {Number} [expandable_number=5] number message show
- * for each click on "show more message"
- * @param {Number} [expandable_default_number=5] number message show
- * on begin before the first click on "show more message"
* @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
* @param {Select} [typeof_thread] inbox/archives/stared/sent
@@ -851,42 +870,25 @@ openerp.mail = function(session) {
default_res_id: 0,
default_parent_id: false }, options.context || {});
- // options
- this.options = _.extend(options.options, {
- 'expandable_number': options.options.expandable_number || 5,
- 'expandable_default_number': options.options.expandable_default_number || 5,
- '_expandable_max': options.options.expandable_default_number || 5,
- 'display_indented_thread': options.options.display_indented_thread || -1,
- 'show_reply_button': options.options.show_reply_button || -1,
- 'typeof_thread': options.options.typeof_thread || 'inbox',
- 'show_header_compose': options.options.show_header_compose || false,
- '_parents': (options.options._parents != undefined ? options.options._parents : []).concat( [this] )
- });
+ this.options = options.options;
+ this.options._parents = (options.options._parents != undefined ? options.options._parents : []).concat( [this] );
// record options and data
this.parent_message= parent.thread!= undefined ? parent : false ;
- // datasets and internal vars
- this.datasets = {
- 'id' : datasets.id || false,
- 'model' : datasets.model || false,
- 'parent_id' : datasets.parent_id || false,
- 'is_private' : datasets.is_private || false,
- 'author_id' : datasets.author_id || false,
- 'thread_level' : (datasets.thread_level+1) || 0,
- 'partner_ids' : []
- };
-
- this.datasets.show_composeform = this.options.show_header_compose && this.options.show_reply_button>this.datasets.thread_level;
-
- for(var i in datasets.partner_ids){
- if(datasets.partner_ids[i][0]!=(datasets.author_id ? datasets.author_id[0] : -1)){
- this.datasets.partner_ids.push(datasets.partner_ids[i]);
- }
- }
-
+ // data of this thread
+ this.id = datasets.id || false,
+ this.model = datasets.model || false,
+ this.parent_id = datasets.parent_id || false,
+ this.is_private = datasets.is_private || false,
+ this.author_id = datasets.author_id || false,
+ this.thread_level = (datasets.thread_level+1) || 0,
+ this.partner_ids = _.filter(datasets.partner_ids, function(partner){ return partner[0]!=datasets.author_id[0]; } )
this.messages = [];
- this.composeMessage = false;
+ this.show_compose_message = this.options.show_compose_message && this.options.show_reply_button > this.thread_level;
+
+ // object compose message
+ this.ComposeMessage = false;
this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model || 'mail.thread');
this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
@@ -894,26 +896,29 @@ openerp.mail = function(session) {
start: function() {
this._super.apply(this, arguments);
- if(this.datasets.show_composeform){
+ if(this.show_compose_message){
this.instantiate_ComposeMessage();
}
this.bind_events();
},
+ /* instantiate the compose message object and insert this on the DOM.
+ * The compose message is display in compact form.
+ */
instantiate_ComposeMessage: function(){
// add message composition form view
- this.composeMessage = new mail.ThreadComposeMessage(this, this.datasets, {
+ this.ComposeMessage = new mail.ThreadComposeMessage(this, this, {
'context': this.context,
'options': this.options,
});
- if(this.datasets.thread_level){
- this.composeMessage.appendTo(this.$el);
+ if(this.thread_level){
+ this.ComposeMessage.appendTo(this.$el);
} else {
// root view
- this.composeMessage.prependTo(this.$el);
+ this.ComposeMessage.prependTo(this.$el);
}
- this.composeMessage.do_hide_compact();
+ this.ComposeMessage.do_hide_compact();
},
/* When the expandable object is visible on screen (with scrolling)
@@ -921,17 +926,18 @@ openerp.mail = function(session) {
*/
on_scroll: function(event){
if(event)event.stopPropagation();
- var message = this.messages[0];
- if(message && message.datasets.type=="expandable" && message.datasets.max_limit){
+ this.$('.oe_msg_expandable:last');
+
+ var message = this.messages[this.messages.length-1];
+ if(message && message.type=="expandable" && message.max_limit){
var pos = message.$el.position();
if(pos.top){
/* bottom of the screen */
var bottom = $(window).scrollTop()+$(window).height()+200;
- if(bottom - pos.top > 0){
+ if(bottom > pos.top){
message.on_expandable();
}
}
-
}
},
@@ -944,27 +950,36 @@ openerp.mail = function(session) {
self.$el.on('click', '.oe_mail_compose_textarea .oe_more_hidden', self.on_hide_recipients);
},
+ /**
+ *show all the partner list of this parent message
+ */
on_show_recipients: function(){
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').show();
p.find('.oe_more').hide();
},
+ /**
+ *hide a part of the partner list of this parent message
+ */
on_hide_recipients: function(){
var p=$(this).parent();
p.find('.oe_more_hidden, .oe_hidden').hide();
p.find('.oe_more').show();
},
- /* get all child message/thread id linked
+ /* get all child message/thread id linked.
+ * @return array of id
*/
get_child_ids: function(){
var res=[];
- _(this.get_childs()).each(function (val, key) { res.push(val.datasets.id); });
+ _(this.get_childs()).each(function (val, key) { res.push(val.id); });
return res;
},
- /* get all child message/thread linked
+ /* get all child message/thread linked.
+ * @param {int} nb_thread_level, number of traversed thread level for this search
+ * @return array of thread object
*/
get_childs: function(nb_thread_level){
var res=[];
@@ -979,7 +994,9 @@ openerp.mail = function(session) {
return res;
},
- /** browse thread
+ /**
+ *search a thread in all thread and child thread.
+ * This method return an object thread.
* @param {object}{int} option.id
* @param {object}{string} option.model
* @param {object}{boolean} option._go_thread_wall
@@ -995,7 +1012,7 @@ openerp.mail = function(session) {
return this.options._parents[0].browse_thread(options);
}
- if(this.datasets.id==options.id){
+ if(this.id==options.id){
return this;
}
@@ -1015,54 +1032,66 @@ openerp.mail = function(session) {
return false;
},
- /** browse message
+ /**
+ *search a message in all thread and child thread.
+ * This method return an object message.
* @param {object}{int} option.id
* @param {object}{string} option.model
* @param {object}{boolean} option._go_thread_wall
* private for check the top thread
- * @return thread object
+ * @return message object
*/
browse_message: function(options){
if(this.options._parents[0].messages[0])
return this.options._parents[0].messages[0].browse_message(options);
},
- /* this function is launch when a user click on "Reply" button
+ /**
+ *If ComposeMessage doesn't exist, instantiate the compose message.
+ * Call the on_compose_expandable method to allow the user to write his message.
+ * (Is call when a user click on "Reply" button)
*/
on_compose_message: function(){
- this.composeMessage.on_compose_expandable();
+ if(!this.ComposeMessage){
+ this.instantiate_ComposeMessage();
+ this.ComposeMessage.do_hide_compact();
+ }
+
+ this.ComposeMessage.on_compose_expandable();
},
- /* display the no message on the thread
+ /**
+ *display the message "there are no message" on the thread
*/
no_message: function(){
$(session.web.qweb.render('mail.wall_no_message', {})).appendTo(this.$el);
},
- /** Fetch messages
- * @param {Bool} initial_mode: initial mode: try to use message_data or
- * message_ids, if nothing available perform a message_read; otherwise
- * directly perform a message_read
+ /**
+ *make a request to read the message (calling RPC to "message_read").
+ * The result of this method is send to the switch message for sending ach message to
+ * his parented object thread.
* @param {Array} replace_domain: added to this.domain
* @param {Object} replace_context: added to this.context
+ * @param {Array} ids read (if the are some ids, the method don't use the domain)
*/
- message_fetch: function (initial_mode, replace_domain, replace_context, ids, callback) {
+ message_fetch: function (replace_domain, replace_context, ids) {
var self = this;
- // initial mode: try to use message_data or message_ids
- if (initial_mode && this.options.message_data) {
- return this.create_message_object(this.options.message_data);
- }
// domain and context: options + additional
fetch_domain = replace_domain ? replace_domain : this.domain;
fetch_context = replace_context ? replace_context : this.context;
- var message_loaded = [this.datasets.id||0].concat( self.options._parents[0].get_child_ids() );
+ var message_loaded = [this.id||0].concat( self.options._parents[0].get_child_ids() );
return this.ds_message.call('message_read', [ids, fetch_domain, message_loaded, fetch_context, this.context.default_parent_id || undefined]
).then(this.proxy('switch_new_message'));
},
- /* create record object and linked him
+ /**
+ *create the message object and attached on this thread.
+ * When the message object is create, this method call insert_message for,
+ * displaying this message on the DOM.
+ * @param : {object} data from calling RPC to "message_read"
*/
create_message_object: function (data) {
var self = this;
@@ -1073,10 +1102,10 @@ openerp.mail = function(session) {
'context': {
'default_model': data.model || self.context.default_model,
'default_res_id': data.res_id || self.context.default_res_id,
- 'default_parent_id': self.datasets.id },
+ 'default_parent_id': self.id },
});
} else {
- var message = new mail.ThreadMessage(self, _.extend(data, {'thread_level': self.datasets.thread_level}), {
+ var message = new mail.ThreadMessage(self, _.extend(data, {'thread_level': self.thread_level}), {
'domain': data.domain,
'context': {
'default_model': data.model,
@@ -1086,23 +1115,39 @@ openerp.mail = function(session) {
});
}
+ // insert the message on dom
+ self.insert_message( message );
+
// check if the message is already create
for(var i in self.messages){
- if(self.messages[i].datasets.id == message.datasets.id){
+ if(self.messages[i].id == message.id){
self.messages[i].destroy();
- self.messages[i] = self.insert_message(message);
- return true;
+ if(message.id>0){
+ self.messages[i] = message;
+ return true;
+ } else {
+ delete self.messages[i];
+ }
}
}
- self.messages.push( self.insert_message(message) );
+ self.messages.push( message );
},
- /** Displays a message or an expandable message */
+ /**
+ *insert the message on the DOM.
+ * All message (and expandable message) are sorted. The method get the
+ * older and newer message to insert the message (before, after).
+ * If there are no older or newer, the message is prepend or append to
+ * the thread (parent object or on root thread for flat view).
+ * The sort is define by the thread_level (O for newer on top).
+ * @param : {object} ThreadMessage object
+ */
insert_message: function (message) {
var self=this;
- if(this.datasets.show_composeform){
- this.composeMessage.do_show_compact();
+ if(this.show_compose_message &&
+ this.options.display_indented_thread > self.thread_level){
+ this.ComposeMessage.do_show_compact();
}
this.$('.oe_wall_no_message').remove();
@@ -1110,32 +1155,32 @@ openerp.mail = function(session) {
// insert on hierarchy display => insert in self child
var thread_messages = self.messages;
var thread = self;
- if( self.options.display_indented_thread < self.datasets.thread_level ) {
+ if( self.options.display_indented_thread < self.thread_level ) {
var thread = self.options._parents[self.options.display_indented_thread] || self.options._parents[0];
var thread_messages = [];
_(thread.get_childs()).each(function (val, key) { thread_messages.push(val.parent_message); });
}
- // check older and newer message for insert
+ // check older and newer message for insertion
var parent_newer = false;
var parent_older = false;
- for(var i in thread_messages){
- if((thread_messages[i].datasets.id > message.datasets.id && message.datasets.id > 0) ||
- thread_messages[i].datasets.id < 0){
- if(!parent_newer ||
- thread_messages[i].datasets.id < 0 ||
- parent_newer.datasets.id >= thread_messages[i].datasets.id) {
- parent_newer = thread_messages[i];
- }
- } else if((thread_messages[i].datasets.id > 0 && thread_messages[i].datasets.id < message.datasets.id) || message.datasets.id < 0) {
- if(!parent_older ||
- parent_older.datasets.id < thread_messages[i].datasets.id) {
- parent_older = thread_messages[i];
+ if(message.id > 0){
+ for(var i in thread_messages){
+ if(thread_messages[i].id > message.id){
+ if(!parent_newer ||
+ parent_newer.id > thread_messages[i].id) {
+ parent_newer = thread_messages[i];
+ }
+ } else if(thread_messages[i].id > 0 && thread_messages[i].id < message.id) {
+ if(!parent_older ||
+ parent_older.id < thread_messages[i].id) {
+ parent_older = thread_messages[i];
+ }
}
}
}
- var sort = self.datasets.thread_level;
+ var sort = (!!self.thread_level || message.id<0);
if(parent_older){
if(sort){
@@ -1144,13 +1189,13 @@ openerp.mail = function(session) {
message.insertBefore(parent_older.$el);
}
} else if(parent_newer){
- if(sort || parent_newer.datasets.id<0){
+ if(sort || parent_newer.id<0){
message.insertBefore(parent_newer.$el);
} else {
message.insertAfter(parent_newer.thread ? parent_newer.thread.$el : parent_newer.$el);
}
} else {
- if(sort) {
+ if(sort && message.id>0) {
message.prependTo(thread.$el);
} else {
message.appendTo(thread.$el);
@@ -1160,7 +1205,11 @@ openerp.mail = function(session) {
return message
},
- /* Send the records to his parent thread */
+ /**
+ *get the parent thread of the messages.
+ * Each message is send to his parent object for creating the object message.
+ * @param : {Array} datas from calling RPC to "message_read"
+ */
switch_new_message: function(records) {
var self=this;
_(records).each(function(record){
@@ -1172,8 +1221,8 @@ openerp.mail = function(session) {
},
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* mail : root Widget
* ------------------------------------------------------------
*
@@ -1202,13 +1251,37 @@ openerp.mail = function(session) {
*... @param {int} [show_read_unread_button] number thread level to display the read/unread button
*... @param {int} [display_indented_thread] number thread level to indented threads.
* other are on flat mode
+ *... @param {Boolean} [show_compose_message] allow to display the composer
+ *... @param {Boolean} [show_compact_message] display the compact message on the thread
+ * when the user clic on this compact mode, the composer is open
*/
init: function (parent, options) {
this._super(parent);
- this.options = options || {};
- this.options.domain = options.domain || [];
- this.options.context = options.context || {};
+ this.domain = options.domain || [];
+ this.context = options.context || {};
this.search_results = {'domain': [], 'context': {}, 'groupby': {}};
+
+ this.options = _.extend({
+ 'typeof_thread' : 'inbox',
+ 'display_indented_thread' : -1,
+ 'show_reply_button' : -1,
+ 'show_read_unread_button' : -1,
+ 'truncate_limit' : 250,
+ 'show_record_name' : false,
+ 'show_compose_message' : false,
+ 'show_compact_message' : false
+ }, options);
+
+ if(this.display_indented_thread === false) {
+ this.display_indented_thread = -1;
+ }
+ if(this.show_reply_button === false) {
+ this.show_reply_button = -1;
+ }
+ if(this.show_read_unread_button === false) {
+ this.show_read_unread_button = -1;
+ }
+
},
start: function (options) {
@@ -1217,31 +1290,31 @@ openerp.mail = function(session) {
this.bind_events();
},
+
/**
- * Display the threads
- */
+ *Create the root thread and display this object in the DOM.
+ * Call the no_message method then c all the message_fetch method
+ * of this root thread to display the messages.
+ */
message_render: function (search) {
+
this.thread = new mail.Thread(this, {}, {
- 'domain' : this.options.domain,
- 'context' : this.options.context,
- 'options': {
- 'typeof_thread': this.options.typeof_thread || 'inbox',
- 'display_indented_thread': this.options.display_indented_thread || 1,
- 'show_reply_button': this.options.show_reply_button || 1,
- 'show_read_unread_button': this.options.show_read_unread_button || 1,
- 'truncate_limit': this.options.truncate_limit || 250,
- 'show_record_name': this.options.show_record_name || false,
- 'show_header_compose': this.options.show_header_compose || false
- },
+ 'domain' : this.domain,
+ 'context' : this.context,
+ 'options': this.options,
});
this.thread.appendTo( this.$el );
this.thread.no_message();
this.thread.message_fetch();
+
+ if(this.options.show_compose_message){
+ this.thread.ComposeMessage.do_show_compact();
+ }
},
bind_events: function(){
- if(this.options.context['typeof_thread']!='other'){
+ if(this.context['typeof_thread']!='other'){
$(document).scroll( this.thread.on_scroll );
$(window).resize( this.thread.on_scroll );
window.setTimeout( this.thread.on_scroll, 500 );
@@ -1250,8 +1323,8 @@ openerp.mail = function(session) {
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* mail_thread Widget
* ------------------------------------------------------------
*
@@ -1280,6 +1353,7 @@ openerp.mail = function(session) {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
render_value: function() {
+ var self = this;
if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
this.$('oe_mail_thread').hide();
return;
@@ -1293,7 +1367,7 @@ openerp.mail = function(session) {
var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
// TDE note: replace message_is_follower by a check in message_follower_ids, as message_is_follower is not used in views anymore
- var show_header_compose = this.view.is_action_enabled('edit') ||
+ var show_compose_message = this.view.is_action_enabled('edit') ||
(this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
if(this.root){
@@ -1304,10 +1378,10 @@ openerp.mail = function(session) {
'domain' : domain,
'context' : this.options.context,
'typeof_thread': this.options.context['typeof_thread'] || 'other',
- 'display_indented_thread': false,
- 'show_reply_button': false,
- 'show_read_unread_button': false,
- 'show_header_compose': show_header_compose
+ 'display_indented_thread': -1,
+ 'show_reply_button': 10,
+ 'show_read_unread_button': -1,
+ 'show_compose_message': show_compose_message
}
);
@@ -1316,8 +1390,8 @@ openerp.mail = function(session) {
});
- /**
- * ------------------------------------------------------------
+ /**
+ * ------------------------------------------------------------
* Wall Widget
* ------------------------------------------------------------
*
@@ -1392,7 +1466,7 @@ openerp.mail = function(session) {
/**
- * Display the threads
+ *Create the root thread widget and display this object in the DOM
*/
message_render: function (search) {
var domain = this.options.domain.concat(this.search_results['domain']);
@@ -1402,24 +1476,26 @@ openerp.mail = function(session) {
'context' : context,
'typeof_thread': context['typeof_thread'] || 'other',
'display_indented_thread': 2,
- 'show_reply_button': 2,
- 'show_read_unread_button': 3,
- 'show_header_compose': true
+ 'show_reply_button': 10,
+ 'show_read_unread_button': 11,
+ 'show_compose_message': true,
+ 'show_compact_message': true
}
);
+
return this.root.appendTo( this.$('.oe_mail_wall_threads:first') );
},
bind_events: function(){
var self=this;
- this.$("button.oe_write_full:first").click(function(){ self.root.thread.composeMessage.on_compose_fullmail(); });
+ this.$("button.oe_write_full:first").click(function(){ self.root.thread.ComposeMessage.on_compose_fullmail(); });
this.$("button.oe_write_onwall:first").click(function(){ self.root.thread.on_compose_message(); });
}
});
/**
- * ------------------------------------------------------------
+ * ------------------------------------------------------------
* UserMenu
* ------------------------------------------------------------
*
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index 735b3e00e0b..f08991be2cc 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -39,6 +39,7 @@ openerp_mail_followers = function(session, mail) {
this._check_visibility();
this.reinit();
this.bind_events();
+ this._super();
},
_check_visibility: function() {
@@ -72,7 +73,7 @@ openerp_mail_followers = function(session, mail) {
target: 'new',
context: {
'default_res_model': self.view.dataset.model,
- 'default_res_id': self.view.dataset.ids[0]
+ 'default_res_id': self.view.datarecord.id,
},
}
self.do_action(action, {
@@ -85,18 +86,11 @@ openerp_mail_followers = function(session, mail) {
read_value: function () {
var self = this;
- return this.ds_model.read_ids([this.view.dataset.ids[0]], ['message_follower_ids']).pipe(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);
});
},
- set_value: function (value_) {
- this._super(value_);
- // TDE FIXME: render_value is never called... ask to niv
- // TDE TODO: in start, call this._super(), should resolve this issue
- this.render_value();
- },
-
render_value: function () {
this.reinit();
return this.fetch_followers(this.get("value"));
@@ -188,8 +182,7 @@ openerp_mail_followers = function(session, mail) {
display_subtypes:function (data) {
var self = this;
var subtype_list_ul = this.$('.oe_subtypes');
- var records = data[this.view.dataset.ids[0]].message_subtype_data;
-
+ var records = data[this.view.datarecord.id || this.view.dataset.ids[0]].message_subtype_data;
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
@@ -209,7 +202,7 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked',false);
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe_users', [[this.view.dataset.ids[0]], [this.session.uid], context]).pipe(this.proxy('read_value'));
+ return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).pipe(this.proxy('read_value'));
},
do_update_subscription: function (event) {
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index 614a3b5c325..1832b235170 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -17,7 +17,7 @@
<t t-name="mail.compose_message">
<div class="oe_msg oe_msg_composer">
<div class="oe_msg_left">
- <img class="oe_msg_icon" alt="User img" t-attf-src="#{widget.datasets.avatar}"/>
+ <img class="oe_msg_icon" alt="User img" t-attf-src="#{widget.avatar}"/>
</div>
<div class="oe_msg_center">
<div class="oe_msg_content">
@@ -70,8 +70,8 @@
Template used to display attachments in a mail.message
-->
<t t-name="mail.thread.message.attachments">
- <ul t-attf-class="oe_msg_attachments #{widget.datasets.attachment_ids[0]?'':'oe_hidden'}">
- <t t-foreach="widget.datasets.attachment_ids" t-as="attachment">
+ <ul t-attf-class="oe_msg_attachments #{widget.attachment_ids[0]?'':'oe_hidden'}">
+ <t t-foreach="widget.attachment_ids" t-as="attachment">
<li>
<span t-if="(attachment.upload or attachment.percent_loaded&lt;100)" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}" t-attf-name="{attachment.name || attachment.filename}">
<div class="oe_upload_in_process">
@@ -82,7 +82,7 @@
<a t-if="(!attachment.upload or attachment.percent_loaded&gt;=100)" t-att-href="attachment.url" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}">
<t t-raw="attachment.name || attachment.filename"/>
</a>
- <t t-if="widget.options.show_attachment_delete and (!attachment.upload or attachment.percent_loaded&gt;=100)">
+ <t t-if="(!attachment.upload or attachment.percent_loaded&gt;=100)">
<a class="oe_right oe_mail_attachment_delete" title="Delete this attachment" t-attf-data-id="{attachment.id}">x</a>
</t>
@@ -105,13 +105,13 @@
<t t-name="mail.thread.list_recipients">
<div class="oe_mail_list_recipients">
Post to:
- <span t-if="!widget.datasets.is_private" class="oe_all_follower">All Followers</span>
- <t t-if="!widget.datasets.is_private and widget.datasets.partner_ids.length"> and </t>
+ <span t-if="!widget.is_private" class="oe_all_follower">All Followers</span>
+ <t t-if="!widget.is_private and widget.partner_ids.length"> and </t>
<t t-set="inc" t-value="0"/>
- <t t-if="widget.datasets.partner_ids.length" t-foreach="widget.datasets.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
+ <t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
</t>
- <t t-if="widget.datasets.partner_ids.length>=3">
- <span class="oe_more">, <a><t t-raw="widget.datasets.partner_ids.length-3"/> others...</a></span>
+ <t t-if="widget.partner_ids.length>=3">
+ <span class="oe_more">, <a><t t-raw="widget.partner_ids.length-3"/> others...</a></span>
<a class="oe_more_hidden">&lt;&lt;&lt;</a>
</t>
</div>
@@ -174,9 +174,9 @@
-->
<div t-name="mail.record_thread" class="oe_mail_record_wall">
<!-- <h4>History and Comments</h4> -->
- <ul class="oe_mail_wall_threads">
+ <div class="oe_mail_wall_threads">
<!-- contains the document thread -->
- </ul>
+ </div>
</div>
<t t-name="mail.thread">
@@ -185,43 +185,42 @@
<!-- default layout -->
<t t-name="mail.thread.message">
- <div t-attf-class="oe_msg oe_lvl_#{widget.datasets.thread_level} oe_msg_#{widget.datasets.type} oe_msg_#{widget.datasets.to_read?'unread':'read'}">
- <!-- message actions (read/unread, reply, delete...) -->
+ <div t-attf-class="oe_msg oe_lvl_#{widget.thread_level} oe_msg_#{widget.type} oe_msg_#{widget.to_read?'unread':'read'}">
<div class='oe_msg_left'>
- <a t-attf-href="#model=res.partner&amp;id=#{widget.datasets.author_id[0]}" t-att-title="widget.datasets.author_id[1]">
- <img class="oe_msg_icon" t-att-src="widget.datasets.avatar"/>
+ <a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
+ <img class="oe_msg_icon" t-att-src="widget.avatar"/>
</a>
</div>
<div class="oe_msg_center">
<div class='oe_msg_icons'>
- <span class='oe_read' t-if="widget.datasets.show_read_unread_button"><a title="Read" class="oe_e">W</a></span>
- <span class='oe_unread' t-if="widget.datasets.show_read_unread_button"><a title="Set back to unread" class="oe_e">W</a></span>
- <span class='oe_reply' t-if="widget.datasets.show_reply_button"><a title="Reply" class="oe_e">(</a></span>
- <span class='oe_star'><a t-attf-class="oe_e oe_mail_starbox #{widget.datasets.has_stared?'oe_stared':''}">7</a></span>
+ <span class='oe_read' t-if="widget.show_read_unread_button"><a title="Read" class="oe_e">W</a></span>
+ <span class='oe_unread' t-if="widget.show_read_unread_button"><a title="Set back to unread" class="oe_e">W</a></span>
+ <span class='oe_reply' t-if="widget.show_reply_button"><a title="Reply" class="oe_e">(</a></span>
+ <span class='oe_star'><a t-attf-class="oe_e oe_mail_starbox #{widget.has_stared?'oe_stared':''}">7</a></span>
</div>
<!-- message itself -->
<div class="oe_msg_content">
- <h1 t-if="widget.datasets.subject" class="oe_msg_title">
- <t t-raw="widget.datasets.subject"/>
+ <h1 t-if="widget.subject" class="oe_msg_title">
+ <t t-raw="widget.subject"/>
</h1>
<div class="oe_msg_body">
- <t t-if="widget.options.show_record_name and widget.datasets.record_name and (!widget.datasets.subject) and !widget.options.thread_level and !widget.options.display_on_thread[0] and widget.datasets.model!='res.partner'">
- <a class="oe_mail_action_model" t-attf-href="#model=#{widget.datasets.model}&amp;id=#{widget.datasets.res_id}"><t t-raw="widget.datasets.record_name"/></a>
+ <t t-if="widget.options.show_record_name and widget.record_name and (!widget.subject) and !widget.options.thread_level and !widget.options.display_on_thread[0] and widget.model!='res.partner'">
+ <a class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}"><t t-raw="widget.record_name"/></a>
</t>
- <t t-raw="widget.datasets.body"/>
+ <t t-raw="widget.body"/>
</div>
- <t t-if="widget.datasets.attachment_ids.length > 0">
+ <t t-if="widget.attachment_ids.length > 0">
<t t-call="mail.thread.message.attachments"/>
</t>
</div>
<div class="oe_msg_footer">
- from <a t-if="widget.datasets.author_id" t-attf-href="#model=res.partner&amp;id=#{widget.datasets.author_id[0]}"><t t-raw="widget.datasets.author_id[1]"/></a>
- <span t-att-title="widget.datasets.date"><t t-raw="widget.datasets.timerelative"/></span>
- <a t-if="widget.datasets.attachment_ids.length > 0" class="oe_mail_msg_view_attachments">
- <t t-if="widget.datasets.attachment_ids.length == 1">1 Attachment</t>
- <t t-if="widget.datasets.attachment_ids.length > 1"><t t-raw="widget.datasets.attachment_ids.length"/> Attachments</t>
+ from <a t-if="widget.author_id" t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a>
+ <span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span>
+ <a t-if="widget.attachment_ids.length > 0" class="oe_mail_msg_view_attachments">
+ <t t-if="widget.attachment_ids.length == 1">1 Attachment</t>
+ <t t-if="widget.attachment_ids.length > 1"><t t-raw="widget.attachment_ids.length"/> Attachments</t>
</a>
<t t-call="mail.thread.message.vote"/>
</div>
@@ -231,9 +230,9 @@
<!-- expandable message layout -->
<t t-name="mail.thread.expandable">
- <div t-attf-class="oe_msg oe_msg_#{widget.datasets.type} oe_msg_unread">
+ <div t-attf-class="oe_msg oe_msg_#{widget.type} oe_msg_unread">
<div class="oe_msg_content oe_msg_more_message">
- <a class="oe_msg_fetch_more">Load more messages <span t-if="widget.datasets.nb_messages>0">(<t t-raw="widget.datasets.nb_messages"/> messages not display)</span>...</a>
+ <a class="oe_msg_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>
</t>
@@ -254,22 +253,22 @@
<span t-name="mail.thread.message.vote">
<!--
<span class="oe_left oe_mail_vote_count">
- <t t-if='widget.datasets.has_voted'>
+ <t t-if='widget.has_voted'>
You
</t>
- <t t-if='(widget.datasets.vote_nb - (widget.datasets.has_voted ? 1 : 0)) > 0'>
- <t t-if='widget.datasets.has_voted'> and </t>
- <t t-esc="widget.datasets.vote_nb"/> people
+ <t t-if='(widget.vote_nb - (widget.has_voted ? 1 : 0)) > 0'>
+ <t t-if='widget.has_voted'> and </t>
+ <t t-esc="widget.vote_nb"/> people
</t>
- <t t-if='(widget.datasets.vote_nb - (widget.datasets.has_voted ? 1 : 0)) > 0'>
- <t t-raw="(widget.datasets.vote_nb - (widget.datasets.has_voted ? 1 : 0))"/>
+ <t t-if='(widget.vote_nb - (widget.has_voted ? 1 : 0)) > 0'>
+ <t t-raw="(widget.vote_nb - (widget.has_voted ? 1 : 0))"/>
concur
</t>
</span>
<button t-attf-class="oe_msg_vote oe_tag">
<span>
- <t t-if="!widget.datasets.has_voted">Concur</t>
- <t t-if="widget.datasets.has_voted">Respectfully disagree</t>
+ <t t-if="!widget.has_voted">Concur</t>
+ <t t-if="widget.has_voted">Respectfully disagree</t>
</span>
</button>
-->
diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py
index d85988a6c90..2eff59fe0ed 100644
--- a/addons/mail/tests/test_mail.py
+++ b/addons/mail/tests/test_mail.py
@@ -581,11 +581,19 @@ class test_mail(TestMailMockups):
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)
self.mail_group.message_process(cr, uid, None, reply_msg)
+ # TDE note: temp various asserts because of the random bug about msg1.child_ids
+ msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
+ new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
+ self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message (%d) should have msg1 as parent' % (new_msg.id))
# 2. References header
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)
self.mail_group.message_process(cr, uid, None, reply_msg2)
+ # TDE note: temp various asserts because of the random bug about msg1.child_ids
+ msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=1)
+ new_msg = self.mail_message.browse(cr, uid, msg_ids[0])
+ self.assertEqual(new_msg.parent_id, msg1, 'Newly processed mail_message should have msg1 as parent')
# 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',
@@ -595,6 +603,12 @@ class test_mail(TestMailMockups):
group_pigs.refresh()
msg1.refresh()
self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
+ # TDE note: python test + debug because of the random error we see with the next assert
+ if len(msg1.child_ids) != 2:
+ msg_ids = self.mail_message.search(cr, uid, [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], limit=10)
+ for new_msg in self.mail_message.browse(cr, uid, msg_ids):
+ print new_msg.subject, '(id', new_msg.id, ')', 'parent_id:', new_msg.parent_id
+ print '\tchild_ids', [child.id for child in new_msg.child_ids]
self.assertEqual(2, len(msg1.child_ids), 'msg1 should have 2 children now')
def test_60_message_vote(self):
diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml
index ce86e0bacfd..255954e31c1 100644
--- a/addons/mail/wizard/mail_compose_message_view.xml
+++ b/addons/mail/wizard/mail_compose_message_view.xml
@@ -6,14 +6,14 @@
<field name="model">mail.compose.message</field>
<field name="arch" type="xml">
<form string="Compose Email" version="7.0">
- <!-- truly invisible fields for control and options -->
- <field name="composition_mode" nolabel="1" invisible="0"/>
- <field name="model" nolabel="1" invisible="0"/>
- <field name="res_id" nolabel="1" invisible="0"/>
- <field name="parent_id" nolabel="1" invisible="0"/>
- <field name="content_subtype" nolabel="1" invisible="0"/>
- <!-- visible wizard -->
<group>
+ <!-- truly invisible fields for control and options -->
+ <field name="composition_mode" invisible="1"/>
+ <field name="model" invisible="1"/>
+ <field name="res_id" invisible="1"/>
+ <field name="parent_id" invisible="1"/>
+ <field name="content_subtype" invisible="1"/>
+ <!-- visible wizard -->
<field name="subject" placeholder="Subject..."
attrs="{'invisible':[('content_subtype', '=', 'plain')]}"/>/>
<field name="partner_ids" widget="many2many_tags" placeholder="Add contacts to notify..."
diff --git a/addons/mrp/security/ir.model.access.csv b/addons/mrp/security/ir.model.access.csv
index d7213a1c689..6ca9cb3d705 100644
--- a/addons/mrp/security/ir.model.access.csv
+++ b/addons/mrp/security/ir.model.access.csv
@@ -24,7 +24,6 @@ access_account_account,account.account mrp_worker,account.model_account_account,
access_purchase_order_mrp_worker,purchase.order mrp_worker,purchase.model_purchase_order,mrp.group_mrp_user,1,0,0,0
access_purchase_order_line_mrp_worker,purchase.order.line mrp_worker,purchase.model_purchase_order_line,mrp.group_mrp_user,1,0,0,0
access_hr_timesheet_group_mrp_worker,resource.calendar mrp_manager,resource.model_resource_calendar,mrp.group_mrp_manager,1,1,1,1
-access_procurement_stock_worker,procurement.order stock_worker,model_procurement_order,stock.group_stock_user,1,1,1,1
access_procurement_user,procurement.order.user,model_procurement_order,base.group_user,1,1,1,1
access_mrp_production_stock_worker,mrp.production stock_worker,model_mrp_production,stock.group_stock_user,1,0,0,0
access_report_workcenter_load,report.workcenter.load,model_report_workcenter_load,mrp.group_mrp_manager,1,1,1,1
diff --git a/addons/product/i18n/es_EC.po b/addons/product/i18n/es_EC.po
index c26a7b76149..e0e35534803 100644
--- a/addons/product/i18n/es_EC.po
+++ b/addons/product/i18n/es_EC.po
@@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-19 05:14+0000\n"
+"X-Launchpad-Export-Date: 2012-10-20 05:07+0000\n"
"X-Generator: Launchpad (build 16165)\n"
#. module: product
diff --git a/addons/sale/i18n/hu.po b/addons/sale/i18n/hu.po
index e562e415c38..ee50143425d 100644
--- a/addons/sale/i18n/hu.po
+++ b/addons/sale/i18n/hu.po
@@ -7,14 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-09-20 07:29+0000\n"
-"PO-Revision-Date: 2012-05-10 17:41+0000\n"
-"Last-Translator: NOVOTRADE RENDSZERHÁZ ( novotrade.hu ) "
-"<openerp@novotrade.hu>\n"
+"PO-Revision-Date: 2012-10-19 17:22+0000\n"
+"Last-Translator: Herczeg Péter <herczegp@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-19 05:11+0000\n"
+"X-Launchpad-Export-Date: 2012-10-20 05:07+0000\n"
"X-Generator: Launchpad (build 16165)\n"
#. module: sale
@@ -400,7 +399,7 @@ msgstr "Rendelés"
#. module: sale
#: field:sale.order,message_ids:0
msgid "Messages"
-msgstr ""
+msgstr "Üzenetek"
#. module: sale
#: selection:sale.report,month:0
@@ -634,7 +633,7 @@ msgstr "Megerősítés"
#. module: sale
#: view:sale.order:0
msgid "Unread messages"
-msgstr ""
+msgstr "Olvasatlan üzenetek"
#. module: sale
#: field:sale.order,partner_shipping_id:0
@@ -672,7 +671,7 @@ msgstr ""
#. module: sale
#: field:sale.order,message_unread:0
msgid "Unread Messages"
-msgstr ""
+msgstr "Olvasatlan üzenetek"
#. module: sale
#: view:sale.order:0
@@ -1105,7 +1104,7 @@ msgstr ""
#. module: sale
#: model:ir.model,name:sale.model_mail_message
msgid "Message"
-msgstr ""
+msgstr "Üzenet"
#. module: sale
#: field:sale.config.settings,module_warning:0
@@ -1323,7 +1322,7 @@ msgstr ""
#. module: sale
#: field:sale.order,message_is_follower:0
msgid "Is a Follower"
-msgstr ""
+msgstr "követő"
#. module: sale
#: code:addons/sale/sale.py:261
@@ -1638,7 +1637,7 @@ msgstr "Mégsem"
#. module: sale
#: field:sale.order,message_follower_ids:0
msgid "Followers"
-msgstr ""
+msgstr "Követők"
#. module: sale
#: code:addons/sale/sale.py:947
@@ -2012,7 +2011,7 @@ msgstr ""
#. module: sale
#: help:sale.order,message_ids:0
msgid "Messages and communication history"
-msgstr ""
+msgstr "Üzenetek és kommunikáció történet"
#. module: sale
#: view:sale.order:0
diff --git a/addons/stock/security/stock_security.xml b/addons/stock/security/stock_security.xml
index c9f8a03a378..f052c458632 100644
--- a/addons/stock/security/stock_security.xml
+++ b/addons/stock/security/stock_security.xml
@@ -5,6 +5,7 @@
<record id="group_stock_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="base.module_category_warehouse_management"/>
+ <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
<record id="group_stock_manager" model="res.groups">
<field name="name">Manager</field>