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