diff --git a/addons/website_event_questions/models/event.py b/addons/website_event_questions/models/event.py
index 4645d73c4d2..e1b95dcee46 100644
--- a/addons/website_event_questions/models/event.py
+++ b/addons/website_event_questions/models/event.py
@@ -33,10 +33,6 @@ class EventEvent(models.Model):
'title': question.title,
'sequence': question.sequence,
'is_individual': question.is_individual,
- 'answer_ids': [(0, 0, {
- 'name': answer.name,
- 'sequence': answer.sequence,
- }) for answer in question.answer_ids]
})
for question in self.event_type_id.question_ids
]
@@ -81,6 +77,18 @@ class EventQuestion(models.Model):
if any(question.event_type_id and question.event_id for question in self):
raise UserError(_('Question should belong to either event category or event but not both'))
+ @api.model
+ def create(self, vals):
+ event_id = vals.get('event_id', False)
+ if event_id:
+ event = self.env['event.event'].browse([event_id])
+ if event.event_type_id.use_questions and event.event_type_id.question_ids:
+ vals['answer_ids'] = vals.get('answer_ids', []) + [(0, 0, {
+ 'name': answer.name,
+ 'sequence': answer.sequence,
+ }) for answer in event.event_type_id.question_ids.filtered(lambda question: question.title == vals.get('title')).mapped('answer_ids')]
+ return super(EventQuestion, self).create(vals)
+
class EventAnswer(models.Model):
_name = 'event.answer'
diff --git a/addons/website_form/models/models.py b/addons/website_form/models/models.py
index 3c118176ec6..d98eff2ed34 100644
--- a/addons/website_form/models/models.py
+++ b/addons/website_form/models/models.py
@@ -26,12 +26,6 @@ class website_form_model(models.Model):
website_form_default_field_id = fields.Many2one('ir.model.fields', 'Field for custom form data', domain="[('model', '=', model), ('ttype', '=', 'text')]", help="Specify the field which will contain meta and custom form fields datas.")
website_form_label = fields.Char("Label for form action", help="Form action label. Ex: crm.lead could be 'Send an e-mail' and project.issue could be 'Create an Issue'.")
- def _all_inherited_model_ids(self):
- return list(itertools.chain(
- [self.id],
- *(m._all_inherited_model_ids() for m in self.inherited_model_ids)
- ))
-
def _get_form_writable_fields(self):
"""
Restriction of "authorized fields" (fields which can be used in the
@@ -39,16 +33,16 @@ class website_form_model(models.Model):
builders and are writable. By default no field is writable by the
form builder.
"""
- excluded = {
+ included = {
field.name
for field in self.env['ir.model.fields'].sudo().search([
- ('model_id', 'in', self._all_inherited_model_ids()),
- ('website_form_blacklisted', '=', True)
+ ('model_id', '=', self.id),
+ ('website_form_blacklisted', '=', False)
])
}
return {
k: v for k, v in self.get_authorized_fields(self.model).iteritems()
- if k not in excluded
+ if k in included
}
@api.model
diff --git a/addons/website_portal_sale/controllers/main.py b/addons/website_portal_sale/controllers/main.py
index 451b7696076..97bac6161b7 100644
--- a/addons/website_portal_sale/controllers/main.py
+++ b/addons/website_portal_sale/controllers/main.py
@@ -218,20 +218,21 @@ class website_account(website_account):
})
return request.render("website_portal_sale.portal_my_invoices", values)
- @http.route(['/my/invoices/
'], type='http', auth="user", website=True)
- def portal_my_invoices_report(self, invoice_id, **kw):
- invoice = request.env['account.invoice'].browse(invoice_id)
+ @http.route(['/my/invoices/pdf/'], type='http', auth="user", website=True)
+ def portal_get_invoice(self, invoice_id, **kw):
+ invoice = request.env['account.invoice'].browse([invoice_id])
try:
invoice.check_access_rights('read')
invoice.check_access_rule('read')
except AccessError:
return request.render("website.403")
+
# print report as sudo, since it require access to taxes, payment term, ... and portal
# does not have those access rights.
pdf = request.env['report'].sudo().get_pdf([invoice_id], 'account.report_invoice')
pdfhttpheaders = [
- ('Content-Type', 'application/pdf'),
- ('Content-Length', len(pdf)),
+ ('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)),
+ ('Content-Disposition', 'attachment; filename=Invoice.pdf;')
]
return request.make_response(pdf, headers=pdfhttpheaders)
@@ -241,7 +242,7 @@ class website_account(website_account):
partner = request.env['res.users'].browse(request.uid).partner_id
invoices = request.env['account.invoice'].sudo().search_count([('partner_id', '=', partner.id), ('state', 'not in', ['draft', 'cancel'])])
if invoices:
- if 'vat' in partner and (data['vat'] or False) != (partner.vat or False):
+ if 'vat' in data and (data['vat'] or False) != (partner.vat or False):
error['vat'] = 'error'
error_message.append(_('Changing VAT number is not allowed once invoices have been issued for your account. Please contact us directly for this operation.'))
if 'name' in data and (data['name'] or False) != (partner.name or False):
diff --git a/addons/website_portal_sale/views/website_portal_sale_templates.xml b/addons/website_portal_sale/views/website_portal_sale_templates.xml
index 5e3eec666da..5ff48d8de4b 100644
--- a/addons/website_portal_sale/views/website_portal_sale_templates.xml
+++ b/addons/website_portal_sale/views/website_portal_sale_templates.xml
@@ -185,7 +185,7 @@
|
-
+
|
|
|
diff --git a/addons/website_sale_digital/controllers/main.py b/addons/website_sale_digital/controllers/main.py
index 089f2b97f35..b633596a0bf 100644
--- a/addons/website_sale_digital/controllers/main.py
+++ b/addons/website_sale_digital/controllers/main.py
@@ -85,7 +85,7 @@ class WebsiteSaleDigital(website_account):
# Also check for attachments in the product templates
elif res_model == 'product.template':
- P = request.env['product.product']
+ P = request.env['product.product'].sudo()
template_ids = map(lambda x: P.browse(x).product_tmpl_id.id, purchased_products)
if res_id not in template_ids:
return redirect(self.orders_page)
diff --git a/doc/cla/individual/leneo.md b/doc/cla/individual/leneo.md
new file mode 100644
index 00000000000..82cb85f012c
--- /dev/null
+++ b/doc/cla/individual/leneo.md
@@ -0,0 +1,11 @@
+Switzerland, 30/06/2017
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Frederic Siffert frederic@treyvaud.ch https://github.com/leNeo
diff --git a/doc/reference/views.rst b/doc/reference/views.rst
index 74c8188bfab..d1848a701ee 100644
--- a/doc/reference/views.rst
+++ b/doc/reference/views.rst
@@ -237,6 +237,11 @@ Possible children elements of the list view are:
Makes the button ``invisible`` if the record is *not* in one of the
listed states
+
+ .. danger::
+
+ Using ``states`` in combination with ``attrs`` may lead to
+ unexpected results as domains are combined with a logical AND.
``context``
merged into the view's context when performing the button's Odoo call
``confirm``
diff --git a/odoo/addons/base/ir/ir_sequence.py b/odoo/addons/base/ir/ir_sequence.py
index a46f5e95eca..12dd3bb9305 100644
--- a/odoo/addons/base/ir/ir_sequence.py
+++ b/odoo/addons/base/ir/ir_sequence.py
@@ -197,11 +197,11 @@ class IrSequence(models.Model):
year = fields.Date.from_string(date).strftime('%Y')
date_from = '{}-01-01'.format(year)
date_to = '{}-12-31'.format(year)
- date_range = self.env['ir.sequence.date_range'].search([('sequence_id', '=', self.id), ('date_from', '>=', date), ('date_from', '<=', date_to)], order='date_from desc')
+ date_range = self.env['ir.sequence.date_range'].search([('sequence_id', '=', self.id), ('date_from', '>=', date), ('date_from', '<=', date_to)], order='date_from desc', limit=1)
if date_range:
date_to = datetime.strptime(date_range.date_from, '%Y-%m-%d') + timedelta(days=-1)
date_to = date_to.strftime('%Y-%m-%d')
- date_range = self.env['ir.sequence.date_range'].search([('sequence_id', '=', self.id), ('date_to', '>=', date_from), ('date_to', '<=', date)], order='date_to desc')
+ date_range = self.env['ir.sequence.date_range'].search([('sequence_id', '=', self.id), ('date_to', '>=', date_from), ('date_to', '<=', date)], order='date_to desc', limit=1)
if date_range:
date_from = datetime.strptime(date_range.date_to, '%Y-%m-%d') + timedelta(days=1)
date_from = date_from.strftime('%Y-%m-%d')
diff --git a/odoo/addons/base/ir/ir_translation.py b/odoo/addons/base/ir/ir_translation.py
index 445e3564f7f..4ce9038070f 100644
--- a/odoo/addons/base/ir/ir_translation.py
+++ b/odoo/addons/base/ir/ir_translation.py
@@ -241,18 +241,19 @@ class IrTranslation(models.Model):
''' When changing source term of a translation, change its value in db
for the associated object, and the src field.
'''
- for record in self:
- if record.type == 'model':
- model_name, field_name = record.name.split(',')
- model = self.env[model_name]
- field = model._fields[field_name]
- if not callable(field.translate):
- # Make a context without language information, because we want
- # to write on the value stored in db and not on the one
- # associated with the current language. Also not removing lang
- # from context trigger an error when lang is different.
- model.browse(record.res_id).with_context(lang=None).write({field_name: record.source})
- return self.write({'src': self.source})
+ self.ensure_one()
+ if self.type == 'model':
+ model_name, field_name = self.name.split(',')
+ model = self.env[model_name]
+ field = model._fields[field_name]
+ if not callable(field.translate):
+ # Make a context without language information, because we want
+ # to write on the value stored in db and not on the one
+ # associated with the current language. Also not removing lang
+ # from context trigger an error when lang is different.
+ model.browse(self.res_id).with_context(lang=None).write({field_name: self.source})
+ if self.src != self.source:
+ self.write({'src': self.source})
def _search_source(self, operator, value):
''' the source term is stored on 'src' field '''
diff --git a/odoo/addons/base/tests/test_base.py b/odoo/addons/base/tests/test_base.py
index 5a45f00e95c..806a9f7fdea 100644
--- a/odoo/addons/base/tests/test_base.py
+++ b/odoo/addons/base/tests/test_base.py
@@ -526,3 +526,8 @@ class TestGroups(TransactionCase):
# create a cycle and check
a.implied_ids = d
self.assertFalse(a._check_m2m_recursion('implied_ids'))
+
+ def test_res_group_copy(self):
+ a = self.env['res.groups'].with_context(lang='en_US').create({'name': 'A'})
+ b = a.copy()
+ self.assertFalse(a.name == b.name)
diff --git a/odoo/models.py b/odoo/models.py
index b0b8361691a..6949a5b9d45 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -3813,7 +3813,7 @@ class BaseModel(object):
trans_name, source_id, target_id = get_trans(field, old, new)
domain = [('name', '=', trans_name), ('res_id', '=', source_id)]
new_val = new_wo_lang[name]
- if old.env.lang:
+ if old.env.lang and callable(field.translate):
# the new value *without lang* must be the old value without lang
new_wo_lang[name] = old_wo_lang[name]
for vals in Translation.search_read(domain):
@@ -3822,6 +3822,7 @@ class BaseModel(object):
del vals['module'] # duplicated vals is not linked to any module
vals['res_id'] = target_id
if vals['lang'] == old.env.lang and field.translate is True:
+ vals['source'] = old_wo_lang[name]
# the value should be the new value (given by copy())
vals['value'] = new_val
Translation.create(vals)