diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot
index c452e046ca0..94bab447b68 100644
--- a/addons/account/i18n/account.pot
+++ b/addons/account/i18n/account.pot
@@ -2514,11 +2514,18 @@ msgstr ""
#. module: account
#. openerp-web
-#: code:addons/account/static/src/xml/account_reconciliation.xml:227
+#: code:addons/account/static/src/xml/account_reconciliation.xml:229
#, python-format
msgid "Close the statement"
msgstr ""
+#. module: account
+#. openerp-web
+#: code:addons/account/static/src/xml/account_reconciliation.xml:228
+#, python-format
+msgid "Close the statements"
+msgstr ""
+
#. module: account
#: model:ir.model.fields,field_description:account.field_account_bank_statement_date_done
msgid "Closed On"
diff --git a/addons/account/static/src/xml/account_reconciliation.xml b/addons/account/static/src/xml/account_reconciliation.xml
index 00673d149e5..f6b11825a1e 100644
--- a/addons/account/static/src/xml/account_reconciliation.xml
+++ b/addons/account/static/src/xml/account_reconciliation.xml
@@ -224,7 +224,10 @@
-
+
diff --git a/addons/auth_ldap/models/res_company_ldap.py b/addons/auth_ldap/models/res_company_ldap.py
index dfc9070a2e9..05dcb275afa 100644
--- a/addons/auth_ldap/models/res_company_ldap.py
+++ b/addons/auth_ldap/models/res_company_ldap.py
@@ -145,7 +145,7 @@ class CompanyLDAP(models.Model):
ldap_password = conf['ldap_password'] or ''
ldap_binddn = conf['ldap_binddn'] or ''
conn.simple_bind_s(ldap_binddn.encode('utf-8'), ldap_password.encode('utf-8'))
- results = conn.search_st(conf['ldap_base'], ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60)
+ results = conn.search_st(conf['ldap_base'].encode('utf-8'), ldap.SCOPE_SUBTREE, filter, retrieve_attributes, timeout=60)
conn.unbind()
except ldap.INVALID_CREDENTIALS:
_logger.error('LDAP bind failed.')
diff --git a/addons/delivery/models/delivery_carrier.py b/addons/delivery/models/delivery_carrier.py
index 0847c3b2348..543c0feb0b7 100644
--- a/addons/delivery/models/delivery_carrier.py
+++ b/addons/delivery/models/delivery_carrier.py
@@ -120,7 +120,7 @@ class DeliveryCarrier(models.Model):
try:
computed_price = self.get_shipping_price_from_so(order)[0]
self.available = True
- except UserError as e:
+ except ValidationError as e:
# No suitable delivery method found, probably configuration error
_logger.info("Carrier %s: %s, not found", self.name, e.name)
computed_price = 0.0
diff --git a/addons/hr/views/hr_views.xml b/addons/hr/views/hr_views.xml
index 45eb7e7fe2d..ee63c50d0d7 100644
--- a/addons/hr/views/hr_views.xml
+++ b/addons/hr/views/hr_views.xml
@@ -74,7 +74,7 @@
-
+
@@ -96,7 +96,7 @@
-
+
diff --git a/addons/mrp_repair/models/mrp_repair.py b/addons/mrp_repair/models/mrp_repair.py
index 671a934c21b..10c88ff7b62 100644
--- a/addons/mrp_repair/models/mrp_repair.py
+++ b/addons/mrp_repair/models/mrp_repair.py
@@ -488,7 +488,7 @@ class RepairLine(models.Model):
if not self.product_id or not self.product_uom_qty:
return
if partner and self.product_id:
- self.tax_id = partner.property_account_position_id.map_tax(self.product_id.taxes_id).ids
+ self.tax_id = partner.property_account_position_id.map_tax(self.product_id.taxes_id, self.product_id, partner).ids
if self.product_id:
self.name = self.product_id.display_name
self.product_uom = self.product_id.uom_id.id
@@ -550,7 +550,7 @@ class RepairFee(models.Model):
pricelist = self.repair_id.pricelist_id
if partner and self.product_id:
- self.tax_id = partner.property_account_position_id.map_tax(self.product_id.taxes_id).ids
+ self.tax_id = partner.property_account_position_id.map_tax(self.product_id.taxes_id, self.product_id, partner).ids
if self.product_id:
self.name = self.product_id.display_name
self.product_uom = self.product_id.uom_id.id
diff --git a/addons/product/models/res_company.py b/addons/product/models/res_company.py
index 81bdc631177..a2147257a0f 100644
--- a/addons/product/models/res_company.py
+++ b/addons/product/models/res_company.py
@@ -25,3 +25,30 @@ class ResCompany(models.Model):
'fields_id': field.id
})
return new_company
+
+ @api.multi
+ def write(self, values):
+ # When we modify the currency of the company, we reflect the change on the list0 pricelist, if
+ # that pricelist is not used by another company. Otherwise, we create a new pricelist for the
+ # given currency.
+ ProductPricelist = self.env['product.pricelist']
+ currency_id = values.get('currency_id')
+ main_pricelist = self.env.ref('product.list0', False)
+ if currency_id and main_pricelist:
+ nb_companies = self.search_count([])
+ for company in self:
+ if main_pricelist.company_id == company or (main_pricelist.company_id.id is False and nb_companies == 1):
+ main_pricelist.write({'currency_id': currency_id})
+ else:
+ pricelist = ProductPricelist.create({
+ 'name': company.name,
+ 'currency_id': currency_id,
+ })
+ field = self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_product_pricelist')])
+ self.env['ir.property'].create({
+ 'name': 'property_product_pricelist',
+ 'company_id': company.id,
+ 'value_reference': 'product.pricelist,%s' % pricelist.id,
+ 'fields_id': field.id
+ })
+ return super(ResCompany, self).write(values)
diff --git a/addons/stock_account/models/stock.py b/addons/stock_account/models/stock.py
index 0d86a58acdc..331c1f86ed8 100644
--- a/addons/stock_account/models/stock.py
+++ b/addons/stock_account/models/stock.py
@@ -187,6 +187,7 @@ class StockMove(models.Model):
def product_price_update_before_done(self):
tmpl_dict = defaultdict(lambda: 0.0)
# adapt standard price on incomming moves if the product cost_method is 'average'
+ std_price_update = {}
for move in self.filtered(lambda move: move.location_id.usage == 'supplier' and move.product_id.cost_method == 'average'):
product_tot_qty_available = move.product_id.qty_available + tmpl_dict[move.product_id.id]
@@ -195,12 +196,13 @@ class StockMove(models.Model):
new_std_price = move.get_price_unit()
else:
# Get the standard price
- amount_unit = move.product_id.standard_price
+ amount_unit = std_price_update.get(move.product_id.id) or move.product_id.standard_price
new_std_price = ((amount_unit * product_tot_qty_available) + (move.get_price_unit() * move.product_qty)) / (product_tot_qty_available + move.product_qty)
tmpl_dict[move.product_id.id] += move.product_qty
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
move.product_id.with_context(force_company=move.company_id.id).write({'standard_price': new_std_price})
+ std_price_update[move.product_id.id] = new_std_price
@api.multi
def product_price_update_after_done(self):
diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js
index c7cdedb3b66..e5abe467076 100644
--- a/addons/website/static/src/js/website.translator.js
+++ b/addons/website/static/src/js/website.translator.js
@@ -8,6 +8,7 @@ var base = require('web_editor.base');
var translate = require('web_editor.translate');
var website = require('website.website');
var local_storage = require('web.local_storage');
+var utils = require('web.utils');
var qweb = core.qweb;
@@ -31,17 +32,21 @@ website.TopBar.include({
},
edit_master: function (ev) {
ev.preventDefault();
- var $link = $('.js_language_selector a[data-default-lang]');
- if (!$link.length) {
- // Fallback for old website
- var l = false;
- _.each($('.js_language_selector a'), function(a) {
- if (!l || a.href.length < l.href.length) { l = a; }
- });
- $link = $(l);
+
+ var lang = '/' + utils.get_cookie('website_lang');
+
+ var current = document.createElement('a');
+ current.href = window.location.toString();
+ current.search += (current.search ? '&' : '?') + 'enable_editor=1';
+ if (current.pathname.indexOf(lang) === 0) {
+ current.pathname = current.pathname.replace(lang, '');
}
- $link[0].search += ($link[0].search ? '&' : '?') + 'enable_editor=1';
- $link.click();
+
+ var link = document.createElement('a');
+ link.href = '/website/lang/default';
+ link.search += (link.search ? '&' : '?') + 'r=' + encodeURIComponent(current.pathname + current.search + current.hash);
+
+ window.location = link.href;
},
});
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index 9a9ef605118..9970d7f511e 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -165,6 +165,9 @@ class WebsiteEventController(http.Controller):
@http.route(['/event//register'], type='http', auth="public", website=True)
def event_register(self, event, **post):
+ if event.state == 'done':
+ return request.redirect("/event/%s" % slug(event))
+
values = {
'event': event,
'main_object': event,
diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py
index edb473d90e0..f8727a8ac60 100644
--- a/addons/website_event_sale/controllers/main.py
+++ b/addons/website_event_sale/controllers/main.py
@@ -3,6 +3,7 @@
from odoo import http, _
from odoo.addons.website_event.controllers.main import WebsiteEventController
+from odoo.addons.website.models.website import slug
from odoo.http import request
@@ -10,6 +11,9 @@ class WebsiteEventSaleController(WebsiteEventController):
@http.route(['/event//register'], type='http', auth="public", website=True)
def event_register(self, event, **post):
+ if event.state == 'done':
+ return request.redirect("/event/%s" % slug(event))
+
event = event.with_context(pricelist=request.website.get_current_pricelist().id)
values = {
'event': event,
diff --git a/addons/website_mail/controllers/main.py b/addons/website_mail/controllers/main.py
index c966b2bede7..57fb68e1330 100644
--- a/addons/website_mail/controllers/main.py
+++ b/addons/website_mail/controllers/main.py
@@ -11,7 +11,12 @@ from odoo.http import request
def object_shasign(record=False, res_model='', res_id=None, **kw):
""" Generate a sha signature using the current time, database secret and the
record object or the res_model and res_id parameters
- Return the sha signature and the time of generation in a tuple"""
+ Return the sha signature and the time of generation in a tuple
+
+ :deprecated: Support for this SHA1-based signature was discontinued
+ in `_message_post_helper()`, use the `token` parameter
+ to allow posting from public sessions instead.
+ """
secret = request.env['ir.config_parameter'].sudo().get_param('database.secret')
shasign = False
timestamp = int(time())
@@ -24,7 +29,7 @@ def object_shasign(record=False, res_model='', res_id=None, **kw):
def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', sha_in='', sha_time=None, nosubscribe=True, **kw):
""" Generic chatter function, allowing to write on *any* object that inherits mail.thread.
- If a token or a shasign is specified, all logged in users will be able to write a message regardless
+ If a token is specified, all logged in users will be able to write a message regardless
of access rights; if the user is the public user, the message will be posted under the name
of the partner_id of the object (or the public user if there is no partner_id on the object).
@@ -36,12 +41,8 @@ def _message_post_helper(res_model='', res_id=None, message='', token='', token_
:param string token: access token if the object's model uses some kind of public access
using tokens (usually a uuid4) to bypass access rules
:param string token_field: name of the field that contains the token on the object (defaults to 'token')
- :param string sha_in: sha1 hash of the string composed of res_model, res_id and the dabase secret in ir.config_parameter
- if you wish to allow public users to write on the object with some security but you don't want
- to add a token field on the object, the sha-sign prevents public users from writing to any other
- object that the one specified by res_model and res_id
- to generate the shasign, you can import the function object_shasign from this file in your controller
- :param str sha_time: timestamp of sha signature generation (signatures are valid for 24h)
+ :param string sha_in: Deprecated, use `token` and `token_field` instead
+ :param str sha_time: Deprecated, use `token` and `token_field` instead
:param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True)
The rest of the kwargs are passed on to message_post()
@@ -55,14 +56,6 @@ def _message_post_helper(res_model='', res_id=None, message='', token='', token_
else:
if not author_id:
raise NotFound()
- elif sha_in:
- timestamp = int(sha_time)
- secret_sudo = request.env['ir.config_parameter'].sudo().get_param('database.secret')
- shasign = sha1('%s%s%s%s' % (res_model, res_id, secret_sudo, timestamp))
- if sha_in == shasign.hexdigest() and int(time()) < timestamp + 3600 * 24:
- record = record.sudo()
- else:
- raise NotFound()
return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message,
message_type=kw.pop('message_type', "comment"),
subtype=kw.pop('subtype', "mt_comment"),
diff --git a/doc/cla/corporate/bacgroup.md b/doc/cla/corporate/bacgroup.md
index 140a12e2e31..490591c233f 100644
--- a/doc/cla/corporate/bacgroup.md
+++ b/doc/cla/corporate/bacgroup.md
@@ -13,9 +13,9 @@ Leandro Gabriel Di Pasquale dipasquale@bacgroup.net https://github.com/leodipasq
List of contributors:
Allan Daniel Aguilar Archaga aguilar@bacgroup.net https://github.com/allanaguilar
-Cesar Alejandro Rodriguez Castillo rodriguez@bacgroup.net https://github.com/hondurasopen
Dewin Javier Garcia Armijo garcia@bacgroup.net https://github.com/dewingarcia
Jose Reynaldo Cabrera Ayala cabrera@bacgroup.net https://github.com/jcabrera1990
Leandro Gabriel Di Pasquale dipasquale@bacgroup.net https://github.com/leodipasquale
Edwin Omar McClellan Salinas mcclellan@bacgroup.net https://github.com/prometeomcclellan
+Osvaldo Jorge Gentile ogentile@bacgroup.net https://github.com/osvaldo35
Salvatore Josue Trimarchi Pinto trimarchi@bacgroup.net https://github.com/salvatoretrimarchi
diff --git a/doc/cla/individual/gillestephanemeyomesse.md b/doc/cla/individual/gillestephanemeyomesse.md
new file mode 100644
index 00000000000..ba6521e4741
--- /dev/null
+++ b/doc/cla/individual/gillestephanemeyomesse.md
@@ -0,0 +1,11 @@
+Belgium, 2017-02-24
+
+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,
+
+Gilles Meyomesse meyomesse.gilles@gmail.com https://github.com/GillesTephaneMeyomesse
diff --git a/doc/setup/install.rst b/doc/setup/install.rst
index 3a8d45afa89..389050dd4bb 100644
--- a/doc/setup/install.rst
+++ b/doc/setup/install.rst
@@ -228,6 +228,7 @@ Execute the following commands to install Odoo 10.0 Community on your server:
$ sudo postgresql-setup initdb
$ sudo systemctl enable postgresql
$ sudo systemctl start postgresql
+ $ sudo yum install yum-utils
$ sudo yum-config-manager --add-repo=https://nightly.odoo.com/10.0/nightly/rpm/odoo.repo
$ sudo yum install -y odoo
$ sudo systemctl enable odoo