summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/account/project/project_view.xml3
-rw-r--r--addons/analytic/analytic.py2
-rw-r--r--addons/fleet/__openerp__.py1
-rw-r--r--addons/fleet/fleet.py18
-rw-r--r--addons/fleet/fleet_data.xml11
-rw-r--r--addons/fleet/fleet_demo.xml12
-rw-r--r--addons/fleet/fleet_view.xml32
-rw-r--r--addons/fleet/security/fleet_security.xml2
-rw-r--r--addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit_view.xml6
-rw-r--r--addons/mail/__init__.py1
-rw-r--r--addons/mail/controllers/__init__.py3
-rw-r--r--addons/mail/controllers/main.py22
-rw-r--r--addons/mail/mail_message.py16
-rw-r--r--addons/mail/static/src/js/mail.js65
-rw-r--r--addons/mail/static/src/xml/mail.xml10
-rw-r--r--addons/mail/tests/test_mail_base.py1
-rw-r--r--addons/mail/tests/test_mail_features.py4
-rw-r--r--addons/mail/tests/test_mail_message.py11
-rw-r--r--addons/portal/security/ir.model.access.csv1
-rw-r--r--addons/procurement/procurement_view.xml2
-rw-r--r--addons/project/security/ir.model.access.csv1
-rw-r--r--addons/sale/sale_data.xml2
-rw-r--r--addons/survey/survey_view.xml2
23 files changed, 177 insertions, 51 deletions
diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml
index dfb85c89b8a..1a596a4a7a9 100644
--- a/addons/account/project/project_view.xml
+++ b/addons/account/project/project_view.xml
@@ -9,13 +9,13 @@
<field name="arch" type="xml">
<tree toolbar="1" colors="red:state=='pending';grey:state in ('cancelled','close');blue:type=='view'" string="Analytic Accounts">
<field name="complete_name"/>
+ <field name="partner_id"/>
<field name="code"/>
<field name="date"/>
<field name="date_start" invisible="1"/>
<field name="user_id" invisible="1"/>
<field name="manager_id" invisible="1"/>
<field name="parent_id" invisible="1"/>
- <field name="partner_id" invisible="1"/>
<field name="state" invisible="1"/>
<field name="type" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
@@ -50,6 +50,7 @@
<field name="field_parent">child_complete_ids</field>
<field name="arch" type="xml">
<tree colors="blue:state=='pending';grey:state in ('close','cancelled');blue:type=='view'" string="Analytic account" toolbar="1">
+ <field name="name" invisible="1"/>
<field name="complete_name"/>
<field name="code"/>
<field name="debit"/>
diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py
index 782fbc4f3ee..420c6516b38 100644
--- a/addons/analytic/analytic.py
+++ b/addons/analytic/analytic.py
@@ -166,7 +166,7 @@ class account_analytic_account(osv.osv):
_columns = {
'name': fields.char('Account/Contract Name', size=128, required=True),
'complete_name': fields.function(_get_full_name, type='char', string='Full Account Name'),
- 'code': fields.char('Reference', size=24, select=True),
+ 'code': fields.char('Reference', select=True),
'type': fields.selection([('view','Analytic View'), ('normal','Analytic Account'),('contract','Contract or Project'),('template','Template of Contract')], 'Type of Account', required=True,
help="If you select the View Type, it means you won\'t allow to create journal entries using that account.\n"\
"The type 'Analytic account' stands for usual accounts that you only want to use in accounting.\n"\
diff --git a/addons/fleet/__openerp__.py b/addons/fleet/__openerp__.py
index 58ee5bc2d16..681f4290bcf 100644
--- a/addons/fleet/__openerp__.py
+++ b/addons/fleet/__openerp__.py
@@ -22,6 +22,7 @@
'name' : 'Fleet Management',
'version' : '0.1',
'author' : 'OpenERP S.A.',
+ 'sequence': 110,
'category': 'Managing vehicles and contracts',
'website' : 'http://www.openerp.com',
'summary' : 'Vehicle, leasing, insurances, costs',
diff --git a/addons/fleet/fleet.py b/addons/fleet/fleet.py
index db999d41d12..af0a78b5448 100644
--- a/addons/fleet/fleet.py
+++ b/addons/fleet/fleet.py
@@ -333,9 +333,9 @@ class fleet_vehicle(osv.Model):
'company_id': fields.many2one('res.company', 'Company'),
'license_plate': fields.char('License Plate', size=32, required=True, help='License plate number of the vehicle (ie: plate number for a car)'),
'vin_sn': fields.char('Chassis Number', size=32, help='Unique number written on the vehicle motor (VIN/SN number)'),
- 'driver_id': fields.many2one('res.partner', 'Driver', _idhelp='Driver of the vehicle'),
- 'model_id': fields.many2one('fleet.vehicle.model', 'Model', requ_idired=True, help='Model of the vehicle'),
- 'log_fuel': fields.one2many('fleet.vehicle.log.f_iduel', 'vehicle_id', 'Fuel Logs'),
+ 'driver_id': fields.many2one('res.partner', 'Driver', help='Driver of the vehicle'),
+ 'model_id': fields.many2one('fleet.vehicle.model', 'Model', required=True, help='Model of the vehicle'),
+ 'log_fuel': fields.one2many('fleet.vehicle.log.fuel', 'vehicle_id', 'Fuel Logs'),
'log_services': fields.one2many('fleet.vehicle.log.services', 'vehicle_id', 'Services Logs'),
'log_contracts': fields.one2many('fleet.vehicle.log.contract', 'vehicle_id', 'Contracts'),
'acquisition_date': fields.date('Acquisition Date', required=False, help='Date when the vehicle has been bought'),
@@ -468,10 +468,13 @@ class fleet_vehicle_log_fuel(osv.Model):
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
- odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
+ vehicle = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context)
+ odometer_unit = vehicle.odometer_unit
+ driver = vehicle.driver_id.id
return {
'value': {
'odometer_unit': odometer_unit,
+ 'purchaser_id': driver,
}
}
@@ -546,7 +549,6 @@ class fleet_vehicle_log_fuel(osv.Model):
'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
}
_defaults = {
- 'purchaser_id': lambda self, cr, uid, ctx: uid,
'date': fields.date.context_today,
'cost_subtype_id': _get_default_service_type,
'cost_type': 'fuel',
@@ -558,10 +560,13 @@ class fleet_vehicle_log_services(osv.Model):
def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
if not vehicle_id:
return {}
- odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
+ vehicle = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context)
+ odometer_unit = vehicle.odometer_unit
+ driver = vehicle.driver_id.id
return {
'value': {
'odometer_unit': odometer_unit,
+ 'purchaser_id': driver,
}
}
@@ -583,7 +588,6 @@ class fleet_vehicle_log_services(osv.Model):
'notes': fields.text('Notes'),
}
_defaults = {
- 'purchaser_id': lambda self, cr, uid, ctx: uid,
'date': fields.date.context_today,
'cost_subtype_id': _get_default_service_type,
'cost_type': 'services'
diff --git a/addons/fleet/fleet_data.xml b/addons/fleet/fleet_data.xml
index 54be46c90fe..d0d07ade01e 100644
--- a/addons/fleet/fleet_data.xml
+++ b/addons/fleet/fleet_data.xml
@@ -16,6 +16,17 @@
</record>
-->
+ <!-- After installation of the module, open the related menu -->
+ <record id="action_fleet_menu" model="ir.actions.client">
+ <field name="name">Open Fleet Menu</field>
+ <field name="tag">reload</field>
+ <field name="params" eval="{'menu_id': ref('fleet.menu_root')}"/>
+ </record>
+ <record id="base.open_menu" model="ir.actions.todo">
+ <field name="action_id" ref="action_fleet_menu"/>
+ <field name="state">open</field>
+ </record>
+
<record forcecreate="True" id="ir_cron_contract_costs_generator" model="ir.cron">
<field name="name">Generation of contracts costs based on the costs frequency</field>
<field eval="True" name="active" />
diff --git a/addons/fleet/fleet_demo.xml b/addons/fleet/fleet_demo.xml
index 03e8bcd38f1..50eb8a3fab1 100644
--- a/addons/fleet/fleet_demo.xml
+++ b/addons/fleet/fleet_demo.xml
@@ -28,9 +28,9 @@
<field name="color">Black</field>
<field name="location">Grand-Rosiere</field>
<field name="doors">5</field>
- <field name="driver_id" ref="base.res_partner_address_18" />
+ <field name="driver_id" ref="base.user_demo" />
<field name="acquisition_date" eval="time.strftime('%Y-%m-%d 2:00:00')" />
- <field name="state" ref="vehicle_state_active"/>
+ <field name="state_id" ref="vehicle_state_active"/>
<field name="odometer_unit">kilometers</field>
<field name="car_value">20000</field>
<field eval="[(6,0,[ref('vehicle_tag_leasing'),ref('fleet.vehicle_tag_break'),ref('fleet.vehicle_tag_senior')])]" name="tag_ids"/>
@@ -45,7 +45,7 @@
<field name="doors">5</field>
<field name="driver_id" ref="base.res_partner_address_19" />
<field name="acquisition_date" eval="time.strftime('%Y-%m-%d 2:00:00')" />
- <field name="state" ref="vehicle_state_inactive"/>
+ <field name="state_id" ref="vehicle_state_inactive"/>
<field name="odometer_unit">kilometers</field>
<field name="car_value">16000</field>
<field eval="[(6,0,[ref('vehicle_tag_leasing'),ref('fleet.vehicle_tag_compact'),ref('fleet.vehicle_tag_junior')])]" name="tag_ids"/>
@@ -60,7 +60,7 @@
<field name="doors">3</field>
<field name="driver_id" ref="base.res_partner_address_17" />
<field name="acquisition_date" eval="time.strftime('%Y-%m-%d 2:00:00')" />
- <field name="state" ref="vehicle_state_active"/>
+ <field name="state_id" ref="vehicle_state_active"/>
<field name="odometer_unit">kilometers</field>
<field name="car_value">20000</field>
<field eval="[(6,0,[ref('vehicle_tag_leasing'),ref('fleet.vehicle_tag_compact'),ref('fleet.vehicle_tag_senior')])]" name="tag_ids"/>
@@ -75,7 +75,7 @@
<field name="doors">3</field>
<field name="driver_id" ref="base.res_partner_address_16" />
<field name="acquisition_date" eval="time.strftime('%Y-%m-%d 2:00:00')" />
- <field name="state" ref="vehicle_state_active"/>
+ <field name="state_id" ref="vehicle_state_active"/>
<field name="odometer_unit">kilometers</field>
<field name="car_value">20000</field>
<field eval="[(6,0,[ref('vehicle_tag_leasing'),ref('fleet.vehicle_tag_compact'),ref('fleet.vehicle_tag_senior')])]" name="tag_ids"/>
@@ -90,7 +90,7 @@
<field name="doors">5</field>
<field name="driver_id" ref="base.res_partner_address_15" />
<field name="acquisition_date" eval="time.strftime('%Y-%m-%d 2:00:00')" />
- <field name="state" ref="vehicle_state_active"/>
+ <field name="state_id" ref="vehicle_state_active"/>
<field name="odometer_unit">kilometers</field>
<field name="car_value">18000</field>
<field eval="[(6,0,[ref('vehicle_tag_leasing'),ref('fleet.vehicle_tag_compact'),ref('fleet.vehicle_tag_senior')])]" name="tag_ids"/>
diff --git a/addons/fleet/fleet_view.xml b/addons/fleet/fleet_view.xml
index 4d4c74fd297..4d0e6298129 100644
--- a/addons/fleet/fleet_view.xml
+++ b/addons/fleet/fleet_view.xml
@@ -20,7 +20,23 @@
</div>
<notebook>
<page string="Vendors">
- <field name="vendors" widget="many2many_kanban"/>
+ <field name="vendors" widget="many2many_kanban">
+ <kanban quick_create="false" create="true">
+ <field name="name"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div style="position: relative">
+ <a t-if="! read_only_mode" type="delete" style="position: absolute; right: 0; padding: 4px; diplay: inline-block">X</a>
+ <div class="oe_module_vignette">
+ <div class="oe_module_desc">
+ <field name="name"/>
+ </div>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
</page>
</notebook>
</sheet>
@@ -38,11 +54,25 @@
</field>
</record>
+ <record model='ir.ui.view' id='fleet_vehicle_model_search'>
+ <field name="name">fleet.vehicle.model.search</field>
+ <field name="model">fleet.vehicle.model</field>
+ <field name="arch" type="xml">
+ <search string="Vehicles costs" >
+ <field name="brand_id" />
+ <group expand="1" string="Group By...">
+ <filter name="groupby_brand" context="{'group_by' : 'brand_id'}" string="Brand"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
<record model='ir.actions.act_window' id='fleet_vehicle_model_act'>
<field name="name">Vehicle Model</field>
<field name="res_model">fleet.vehicle.model</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
+ <field name="context">{"search_default_groupby_brand" : True,}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new model.
diff --git a/addons/fleet/security/fleet_security.xml b/addons/fleet/security/fleet_security.xml
index daaa0b0cba7..6c718f4cdd7 100644
--- a/addons/fleet/security/fleet_security.xml
+++ b/addons/fleet/security/fleet_security.xml
@@ -8,11 +8,13 @@
<record id="group_fleet_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="module_fleet_category"/>
+ <field name="users" eval="[(4, ref('base.user_demo'))]"/>
</record>
<record id="group_fleet_manager" model="res.groups">
<field name="name">Manager</field>
<field name="implied_ids" eval="[(4, ref('group_fleet_user'))]"/>
<field name="category_id" ref="module_fleet_category"/>
+ <field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="fleet_user_contract_visibility" model="ir.rule">
<field name="name">User can only see his/her contracts</field>
diff --git a/addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit_view.xml b/addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit_view.xml
index 65cbe360598..804b45c2efd 100644
--- a/addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit_view.xml
+++ b/addons/hr_timesheet_invoice/wizard/hr_timesheet_analytic_profit_view.xml
@@ -16,10 +16,8 @@
</div>
</group>
<group>
- <separator string="Journals" colspan="4"/>
- <field name="journal_ids" colspan="4" nolabel="1"/>
- <separator string="Users" colspan="4"/>
- <field name="employee_ids" colspan="4" nolabel="1"/>
+ <field name="journal_ids" widget="many2many_tags"/>
+ <field name="employee_ids" widget="many2many_tags"/>
</group>
</sheet>
<footer>
diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py
index 7c82bfde78d..26578e19af1 100644
--- a/addons/mail/__init__.py
+++ b/addons/mail/__init__.py
@@ -33,5 +33,6 @@ import wizard
import res_config
import mail_group_menu
import update
+import controllers
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/controllers/__init__.py b/addons/mail/controllers/__init__.py
new file mode 100644
index 00000000000..e11f9ba81bb
--- /dev/null
+++ b/addons/mail/controllers/__init__.py
@@ -0,0 +1,3 @@
+import main
+
+# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py
new file mode 100644
index 00000000000..4c6f6e56064
--- /dev/null
+++ b/addons/mail/controllers/main.py
@@ -0,0 +1,22 @@
+import base64
+import openerp.addons.web.http as oeweb
+from openerp.addons.web.controllers.main import content_disposition
+
+#----------------------------------------------------------
+# Controller
+#----------------------------------------------------------
+class MailController(oeweb.Controller):
+ _cp_path = '/mail'
+
+ @oeweb.httprequest
+ def download_attachment(self, req, model, id, method, attachment_id, **kw):
+ Model = req.session.model(model)
+ res = getattr(Model, method)(int(id), int(attachment_id))
+ if res:
+ filecontent = base64.b64decode(res.get('base64'))
+ filename = res.get('filename')
+ if filecontent and filename:
+ return req.make_response(filecontent,
+ headers=[('Content-Type', 'application/octet-stream'),
+ ('Content-Disposition', content_disposition(filename, req))])
+ return req.not_found()
diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 1b187df637a..da679e27ef5 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -205,6 +205,22 @@ class mail_message(osv.Model):
return new_has_voted or False
#------------------------------------------------------
+ # download an attachment
+ #------------------------------------------------------
+
+ def download_attachment(self, cr, uid, id_message, attachment_id, context=None):
+ """ Return the content of linked attachments. """
+ message = self.browse(cr, uid, id_message, context=context)
+ if attachment_id in [attachment.id for attachment in message.attachment_ids]:
+ attachment = self.pool.get('ir.attachment').browse(cr, SUPERUSER_ID, attachment_id, context=context)
+ if attachment.datas and attachment.datas_fname:
+ return {
+ 'base64': attachment.datas,
+ 'filename': attachment.datas_fname,
+ }
+ return False
+
+ #------------------------------------------------------
# Notification API
#------------------------------------------------------
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index a88a8efd3d8..dc5583eb951 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -29,8 +29,13 @@ openerp.mail = function (session) {
},
/* Get the url of an attachment {'id': id} */
- get_attachment_url: function (session, attachment) {
- return session.url('/web/binary/saveas', {model: 'ir.attachment', field: 'datas', filename_field: 'datas_fname', id: attachment['id']});
+ get_attachment_url: function (session, message_id, attachment_id) {
+ return session.url('/mail/download_attachment', {
+ 'model': 'mail.message',
+ 'id': message_id,
+ 'method': 'download_attachment',
+ 'attachment_id': attachment_id
+ });
},
/**
@@ -258,7 +263,7 @@ openerp.mail = function (session) {
for (var l in this.attachment_ids) {
var attach = this.attachment_ids[l];
if (!attach.formating) {
- attach.url = mail.ChatterUtils.get_attachment_url(this.session, attach);
+ attach.url = mail.ChatterUtils.get_attachment_url(this.session, this.id, attach.id);
attach.filetype = mail.ChatterUtils.filetype(attach.filename);
attach.name = mail.ChatterUtils.breakword(attach.name || attach.filename);
attach.formating = true;
@@ -420,18 +425,23 @@ openerp.mail = function (session) {
/* when the file is uploaded
*/
on_attachment_loaded: function (event, result) {
- 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,
- 'url': mail.ChatterUtils.get_attachment_url(this.session, result)
- };
+
+ if (result.erorr || !result.id ) {
+ this.do_warn( session.web.qweb.render('mail.error_upload'), result.error);
+ this.attachment_ids = _.filter(this.attachment_ids, function (val) { return !val.upload; });
+ } else {
+ 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,
+ 'url': mail.ChatterUtils.get_attachment_url(this.session, this.id, result.id)
+ };
+ }
}
}
this.display_attachments();
-
var $input = this.$('input.oe_form_binary_file');
$input.after($input.clone(true)).remove();
this.$(".oe_attachment_file").show();
@@ -484,6 +494,11 @@ openerp.mail = function (session) {
},
on_compose_fullmail: function (default_composition_mode) {
+
+ if(!this.do_check_attachment_upload()) {
+ return false;
+ }
+
if (default_composition_mode == 'reply') {
var context = {
'default_composition_mode': default_composition_mode,
@@ -534,31 +549,31 @@ openerp.mail = function (session) {
this.reinit();
},
+ /* return true if all file are complete else return false and make an alert */
+ do_check_attachment_upload: function () {
+ if (_.find(this.attachment_ids, function (file) {return file.upload;})) {
+ this.do_warn(session.web.qweb.render('mail.error_upload'), session.web.qweb.render('mail.error_upload_please_wait'));
+ return false;
+ } else {
+ return true;
+ }
+ },
+
/*post a message and fetch the message*/
on_message_post: function (event) {
var self = this;
var comment_node = this.$('textarea');
var body = comment_node.val();
- comment_node.val('');
-
- var attachments=[];
- 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.attachment_ids[i].id);
- }
- if (body.match(/\S+/)) {
+ if (this.do_check_attachment_upload() && (this.attachment_ids.length || body.match(/\S+/))) {
//session.web.blockUI();
this.parent_thread.ds_thread.call('message_post_user_api', [
this.context.default_res_id,
body,
false,
this.context.default_parent_id,
- attachments,
+ _.map(this.attachment_ids, function (file) {return file.id;}),
this.parent_thread.context
]).done(function (record) {
var thread = self.parent_thread;
@@ -571,8 +586,8 @@ openerp.mail = function (session) {
var message = thread.create_message_object( data[0] );
// insert the message on dom
thread.insert_message( message, root ? undefined : self.$el, root );
- self.on_cancel();
});
+ self.on_cancel();
//session.web.unblockUI();
});
return true;
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index 640d6c031a5..115047028f5 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -75,7 +75,7 @@
<t t-foreach='widget.attachment_ids' t-as='attachment'>
<t t-if="attachment.filetype !== 'webimage'">
<div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}">
- <a t-att-href='attachment.url'>
+ <a t-att-href='attachment.url' target="_blank">
<img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.filetype + '.png'"></img>
<div class='oe_name'><t t-raw='attachment.name' /></div>
</a>
@@ -87,7 +87,7 @@
</t>
<t t-if="attachment.filetype === 'webimage'">
<div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}">
- <a t-att-href='attachment.url'>
+ <a t-att-href='attachment.url' target="_blank">
<img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img>
<div class='oe_name'><t t-raw='attachment.name' /></div>
</a>
@@ -180,6 +180,12 @@
</t>
<!--
+ error message for uploading
+ -->
+ <t t-name="mail.error_upload">Uploading error</t>
+ <t t-name="mail.error_upload_please_wait">Please, wait while the file is uploading.</t>
+
+ <!--
record_thread main template
Template used to display the communication history in documents
form view.
diff --git a/addons/mail/tests/test_mail_base.py b/addons/mail/tests/test_mail_base.py
index 7811f676232..f9cea33be7f 100644
--- a/addons/mail/tests/test_mail_base.py
+++ b/addons/mail/tests/test_mail_base.py
@@ -50,6 +50,7 @@ class TestMailBase(common.TransactionCase):
# Usefull models
self.ir_model = self.registry('ir.model')
+ self.ir_attachment = self.registry('ir.attachment')
self.mail_alias = self.registry('mail.alias')
self.mail_thread = self.registry('mail.thread')
self.mail_group = self.registry('mail.group')
diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py
index 45142934775..b97c9a4af94 100644
--- a/addons/mail/tests/test_mail_features.py
+++ b/addons/mail/tests/test_mail_features.py
@@ -422,6 +422,10 @@ class test_mail(TestMailBase):
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
self.assertIn((attach.name, attach.datas.decode('base64')), _attachments,
'mail.message attachment name / data incorrect')
+ # Test: download attachments
+ for attach in message2.attachment_ids:
+ dl_attach = self.mail_message.download_attachment(cr, user_raoul.id, id_message=message2.id, attachment_id=attach.id)
+ self.assertIn((dl_attach['filename'], dl_attach['base64'].decode('base64')), _attachments, 'mail.message download_attachment is incorrect')
# 2. Dédé has been notified -> should also have been notified of the parent message
message1.refresh()
diff --git a/addons/mail/tests/test_mail_message.py b/addons/mail/tests/test_mail_message.py
index b93fd27bbed..c544cce8509 100644
--- a/addons/mail/tests/test_mail_message.py
+++ b/addons/mail/tests/test_mail_message.py
@@ -128,12 +128,16 @@ class test_mail_access_rights(TestMailBase):
# Prepare groups: Pigs (employee), Jobs (public)
self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message')
+ # prepare an attachment
+ attachment_id = self.ir_attachment.create(cr, uid, {'datas': 'My attachment'.encode('base64'), 'name': 'doc.txt', 'datas_fname': 'doc.txt'})
+
# ----------------------------------------
# CASE1: read
# ----------------------------------------
# Do: create a new mail.message
- message_id = self.mail_message.create(cr, uid, {'body': 'My Body'})
+ message_id = self.mail_message.create(cr, uid, {'body': 'My Body', 'attachment_ids': [(4, attachment_id)]})
+
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
self.assertRaises(except_orm, self.mail_message.read,
cr, user_bert_id, message_id)
@@ -141,11 +145,16 @@ class test_mail_access_rights(TestMailBase):
notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id})
# Test: Bert reads the message, ok because notification pushed
self.mail_message.read(cr, user_bert_id, message_id)
+ # Test: Bert downloads attachment, ok because he can read message
+ self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id)
# Do: remove notification
self.mail_notification.unlink(cr, uid, notif_id)
# Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc
self.assertRaises(except_orm, self.mail_message.read,
cr, self.user_bert_id, message_id)
+ # Test: Bert downloads attachment, crash because he can't read message
+ self.assertRaises(except_orm, self.mail_message.download_attachment,
+ cr, user_bert_id, message_id, attachment_id)
# Do: Bert is now the author
self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id})
# Test: Bert reads the message, ok because Bert is the author
diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv
index b9f98f81fd7..59ca37e213d 100644
--- a/addons/portal/security/ir.model.access.csv
+++ b/addons/portal/security/ir.model.access.csv
@@ -7,3 +7,4 @@ access_res_partner_category,res.partner_category,base.model_res_partner_category
access_res_partner_title,res.partner_title,base.model_res_partner_title,portal.group_portal,1,0,0,0
access_acquirer,portal.payment.acquirer,portal.model_portal_payment_acquirer,,1,0,0,0
access_acquirer_all,portal.payment.acquirer,portal.model_portal_payment_acquirer,base.group_system,1,1,1,1
+access_ir_attachment_group_portal,ir.attachment group_portal,base.model_ir_attachment,portal.group_portal,1,0,1,0 \ No newline at end of file
diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml
index a0d51c87713..6e5bf24ea6e 100644
--- a/addons/procurement/procurement_view.xml
+++ b/addons/procurement/procurement_view.xml
@@ -281,7 +281,7 @@
groups="stock.group_stock_user"/>
<!-- Procurements are located in Warehouse menu hierarchy, MRP users should come to Stock application to use it. -->
- <menuitem id="menu_stock_sched" name="Schedulers" parent="stock.menu_stock_root" sequence="4"/>
+ <menuitem id="menu_stock_sched" name="Schedulers" parent="stock.menu_stock_root" sequence="4" groups="stock.group_stock_manager"/>
<menuitem action="action_compute_schedulers" id="menu_stock_proc_schedulers" parent="menu_stock_sched" sequence="20" groups="stock.group_stock_manager"/>
<menuitem action="procurement_exceptions" id="menu_stock_procurement_action" parent="menu_stock_sched" sequence="50" groups="stock.group_stock_manager"/>
<menuitem id="menu_stock_procurement" name="Automatic Procurements" parent="stock.menu_stock_configuration" sequence="5"/>
diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv
index d9f6cb9d2f6..a7cf4618993 100644
--- a/addons/project/security/ir.model.access.csv
+++ b/addons/project/security/ir.model.access.csv
@@ -17,6 +17,7 @@ access_project_project_sale_user,project.project salesman,model_project_project,
access_account_analytic_line_project,account.analytic.line project,analytic.model_account_analytic_line,project.group_project_manager,1,1,1,1
access_project_task_history,project.task.history project,project.model_project_task_history,project.group_project_user,1,1,1,0
access_project_task_history_cumulative,project.task.history project,project.model_project_task_history_cumulative,project.group_project_manager,1,0,0,0
+access_project_task_history_cumulative,project.task.history project,project.model_project_task_history_cumulative,project.group_project_user,1,0,0,0
access_resource_calendar,project.resource_calendar manager,resource.model_resource_calendar,project.group_project_manager,1,0,0,0
access_project_category,project.project_category,model_project_category,,1,0,0,0
access_project_category_manager,project.project_category,model_project_category,project.group_project_manager,1,1,1,1
diff --git a/addons/sale/sale_data.xml b/addons/sale/sale_data.xml
index 3fe03966da2..395922c7d64 100644
--- a/addons/sale/sale_data.xml
+++ b/addons/sale/sale_data.xml
@@ -22,7 +22,7 @@
<!-- Resource: sale.shop -->
<record id="sale_shop_1" model="sale.shop">
<field name="company_id" ref="base.main_company"/>
- <field name="payment_default_id" ref="account.account_payment_term"/>
+ <field name="payment_default_id" ref="account.account_payment_term_net"/>
<field name="pricelist_id" ref="product.list0"/>
<!-- Copy the name of any company. Without demo data this will yield
diff --git a/addons/survey/survey_view.xml b/addons/survey/survey_view.xml
index 22589244a53..7da3f26fc2f 100644
--- a/addons/survey/survey_view.xml
+++ b/addons/survey/survey_view.xml
@@ -9,7 +9,7 @@
<menuitem name="Reporting" parent="base.menu_tools"
id="base.menu_lunch_reporting" sequence="6"/>
<menuitem name="Reporting" id="menu_reporting" parent="menu_surveys" sequence="60"/>
- <menuitem id="base.next_id_10" name="Survey" parent="base.menu_reporting" sequence="1" />
+ <menuitem id="base.next_id_10" name="Survey" parent="base.menu_reporting" sequence="1" groups="base.group_survey_user"/>
<!--
Survey