diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-03-08 19:00:04 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-03-08 19:00:04 +0100 |
| commit | a0aa939d9b8440ae1223e103d70ae84455a1f9bc (patch) | |
| tree | 129d0dd58abc42457ee4cbd8072d4059e2f24a2a | |
| parent | 8f118ad5338878f399b02edba2440442e14cc1ab (diff) | |
| parent | fcb48b724152db876f6752560cce5a5d875e8f46 (diff) | |
[MERGE] forward port branch 11.0 up to fcb48b72415
| -rw-r--r-- | addons/payment_ogone/controllers/main.py | 3 | ||||
| -rw-r--r-- | addons/payment_ogone/models/payment.py | 18 | ||||
| -rw-r--r-- | addons/portal/controllers/mail.py | 4 | ||||
| -rw-r--r-- | addons/project/models/project.py | 2 | ||||
| -rw-r--r-- | addons/purchase/tests/test_fifo_price.py | 4 | ||||
| -rw-r--r-- | addons/sale_timesheet/models/sale_order.py | 2 | ||||
| -rw-r--r-- | addons/stock/models/stock_quant.py | 10 | ||||
| -rw-r--r-- | addons/stock_dropshipping/tests/test_lifo_price.py | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_renderer.js | 2 | ||||
| -rw-r--r-- | addons/web/static/tests/core/util_tests.js | 11 | ||||
| -rw-r--r-- | addons/website/models/website.py | 2 | ||||
| -rw-r--r-- | addons/website/static/src/js/menu/content.js | 2 | ||||
| -rw-r--r-- | doc/cla/individual/true-datura.md | 11 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/models.py | 4 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/tests/test_onchange.py | 29 | ||||
| -rw-r--r-- | odoo/models.py | 19 |
17 files changed, 94 insertions, 35 deletions
diff --git a/addons/payment_ogone/controllers/main.py b/addons/payment_ogone/controllers/main.py index 8680e99fda5..1d03a688630 100644 --- a/addons/payment_ogone/controllers/main.py +++ b/addons/payment_ogone/controllers/main.py @@ -2,6 +2,7 @@ import logging import pprint import werkzeug +from werkzeug.urls import url_unquote_plus from odoo import http from odoo.http import request @@ -26,7 +27,7 @@ class OgoneController(http.Controller): """ Ogone contacts using GET, at least for accept """ _logger.info('Ogone: entering form_feedback with post data %s', pprint.pformat(post)) # debug request.env['payment.transaction'].sudo().form_feedback(post, 'ogone') - return werkzeug.utils.redirect(post.pop('return_url', '/')) + return werkzeug.utils.redirect(url_unquote_plus(post.pop('return_url', '/'))) @http.route(['/payment/ogone/s2s/create_json'], type='json', auth='public', csrf=False) def ogone_s2s_create_json(self, **kwargs): diff --git a/addons/payment_ogone/models/payment.py b/addons/payment_ogone/models/payment.py index 6ec49776f55..09df4b52bc4 100644 --- a/addons/payment_ogone/models/payment.py +++ b/addons/payment_ogone/models/payment.py @@ -150,6 +150,9 @@ class PaymentAcquirerOgone(models.Model): def ogone_form_generate_values(self, values): base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') ogone_tx_values = dict(values) + param_plus = { + 'return_url': ogone_tx_values.pop('return_url', False) + } temp_ogone_tx_values = { 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], @@ -167,7 +170,7 @@ class PaymentAcquirerOgone(models.Model): 'DECLINEURL': urls.url_join(base_url, OgoneController._decline_url), 'EXCEPTIONURL': urls.url_join(base_url, OgoneController._exception_url), 'CANCELURL': urls.url_join(base_url, OgoneController._cancel_url), - 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop('return_url') if ogone_tx_values.get('return_url') else False, + 'PARAMPLUS': url_encode(param_plus), } if self.save_token in ['ask', 'always']: temp_ogone_tx_values.update({ @@ -210,8 +213,8 @@ class PaymentAcquirerOgone(models.Model): class PaymentTxOgone(models.Model): _inherit = 'payment.transaction' # ogone status - _ogone_valid_tx_status = [5, 9] - _ogone_wait_tx_status = [41, 50, 51, 52, 55, 56, 91, 92, 99] + _ogone_valid_tx_status = [5, 9, 8] + _ogone_wait_tx_status = [41, 50, 51, 52, 55, 56, 91, 92, 99, 81, 82] _ogone_pending_tx_status = [46] # 3DS HTML response _ogone_cancel_tx_status = [1] @@ -410,13 +413,12 @@ class PaymentTxOgone(models.Model): 'ORDERID': reference, 'AMOUNT': int(self.amount * 100), 'CURRENCY': self.currency_id.name, - 'OPERATION': 'RFD', - 'ECI': 2, # Recurring (from MOTO) - 'ALIAS': self.payment_token_id.acquirer_ref, - 'RTIMEOUT': 30, + 'OPERATION': 'RFS', + 'PAYID': self.acquirer_reference, } + data['SHASIGN'] = self.acquirer_id._ogone_generate_shasign('in', data) - direct_order_url = 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % (self.acquirer_id.environment) + direct_order_url = 'https://secure.ogone.com/ncol/%s/maintenancedirect.asp' % (self.acquirer_id.environment) logged_data = data.copy() logged_data.pop('PSWD') diff --git a/addons/portal/controllers/mail.py b/addons/portal/controllers/mail.py index 3a59ecd70b3..b8ff6f8f2fd 100644 --- a/addons/portal/controllers/mail.py +++ b/addons/portal/controllers/mail.py @@ -5,6 +5,7 @@ from werkzeug.exceptions import NotFound, Forbidden from odoo import http from odoo.http import request +from odoo.osv import expression from odoo.tools import consteq @@ -95,6 +96,9 @@ class PortalChatter(http.Controller): access_as_sudo = _has_token_access(res_model, res_id, token=kw.get('token')) if not access_as_sudo: # if token is not correct, raise Forbidden raise Forbidden() + # Non-employee see only messages with not internal subtype (aka, no internal logs) + if not request.env['res.users'].has_group('base.group_user'): + domain = expression.AND([['&', '&', ('subtype_id', '!=', False), ('subtype_id.internal', '=', False)], domain]) Message = request.env['mail.message'].sudo() return { 'messages': Message.search(domain, limit=limit, offset=offset).portal_message_format(), diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 054f5ad4b09..b561d5bcfcf 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -433,7 +433,7 @@ class Task(models.Model): _date_name = "date_start" _inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin', 'rating.mixin'] _mail_post_access = 'read' - _order = "priority desc, sequence, date_start, name, id" + _order = "priority desc, sequence, id desc" @api.model def default_get(self, fields_list): diff --git a/addons/purchase/tests/test_fifo_price.py b/addons/purchase/tests/test_fifo_price.py index dc26f4dc9a4..8b43da71fc9 100644 --- a/addons/purchase/tests/test_fifo_price.py +++ b/addons/purchase/tests/test_fifo_price.py @@ -13,10 +13,6 @@ class TestFifoPrice(TestPurchase): self._load('account', 'test', 'account_minimal_test.xml') self._load('stock_account', 'test', 'stock_valuation_account.xml') - # Set the company currency as EURO for the sake of repeatibility - self.env.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", - [self.env.ref("base.EUR").id, self.env.ref('base.main_company').id]) - # Set a product as using fifo price product_icecream = self.env['product.product'].create({ 'default_code': 'FIFO', diff --git a/addons/sale_timesheet/models/sale_order.py b/addons/sale_timesheet/models/sale_order.py index 83a0c1b82d2..2116722d9d0 100644 --- a/addons/sale_timesheet/models/sale_order.py +++ b/addons/sale_timesheet/models/sale_order.py @@ -138,7 +138,7 @@ class SaleOrderLine(models.Model): qty_delivered_method = fields.Selection(selection_add=[('timesheet', 'Timesheets')]) task_id = fields.Many2one('project.task', 'Task', index=True, help="Task generated by the sales order item") - is_service = fields.Boolean("Is a Service", compute='_compute_is_service', store=True, help="Sales Order item should generate a task and/or a project, depending on the product settings.") + is_service = fields.Boolean("Is a Service", compute='_compute_is_service', store=True, compute_sudo=True, help="Sales Order item should generate a task and/or a project, depending on the product settings.") analytic_line_ids = fields.One2many(domain=[('project_id', '=', False)]) # only analytic lines, not timesheets (since this field determine if SO line came from expense) @api.multi diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 3b1c27d9eb2..bfd6e52acf4 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -58,10 +58,14 @@ class StockQuant(models.Model): action = self.env.ref('stock.stock_move_line_action').read()[0] action['domain'] = [ ('product_id', '=', self.product_id.id), - '|', ('location_id', '=', self.location_id.id), - ('location_dest_id', '=', self.location_id.id), + '|', + ('location_id', '=', self.location_id.id), + ('location_dest_id', '=', self.location_id.id), ('lot_id', '=', self.lot_id.id), - ('package_id', '=', self.package_id.id)] + '|', + ('package_id', '=', self.package_id.id), + ('result_package_id', '=', self.package_id.id), + ] return action @api.constrains('product_id') diff --git a/addons/stock_dropshipping/tests/test_lifo_price.py b/addons/stock_dropshipping/tests/test_lifo_price.py index fc1c0850ab7..9ffd4c60b8b 100644 --- a/addons/stock_dropshipping/tests/test_lifo_price.py +++ b/addons/stock_dropshipping/tests/test_lifo_price.py @@ -17,10 +17,6 @@ class TestLifoPrice(common.TransactionCase): self._load('account', 'test', 'account_minimal_test.xml') self._load('stock_account', 'test', 'stock_valuation_account.xml') - # Set the company currency as EURO for the sake of repeatibility - self.env.cr.execute("UPDATE res_company SET currency_id = %s WHERE id = %s", - [self.env.ref("base.EUR").id, self.env.ref('base.main_company').id]) - # Set product category removal strategy as LIFO product_category_001 = self.env['product.category'].create({ 'name': 'Lifo Category', diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 251cd2b508c..ffeb4a1de87 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -228,7 +228,7 @@ var utils = { * @returns {boolean} */ is_bin_size: function (v) { - return (/^\d+(\.\d*)? \w+$/).test(v); + return (/^\d+(\.\d*)? [^0-9]+$/).test(v); }, /** * @param {any} node diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 27cdf23b18b..977674c022a 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -617,7 +617,7 @@ var BasicRenderer = AbstractRenderer.extend({ */ _renderWidget: function (record, node) { var Widget = widgetRegistry.get(node.attrs.name); - var widget = new Widget(this, record); + var widget = new Widget(this, record, node); this.widgets.push(widget); diff --git a/addons/web/static/tests/core/util_tests.js b/addons/web/static/tests/core/util_tests.js index 204503117e6..c7158083dcb 100644 --- a/addons/web/static/tests/core/util_tests.js +++ b/addons/web/static/tests/core/util_tests.js @@ -44,6 +44,17 @@ QUnit.module('core', {}, function () { assert.strictEqual(intersperse("12345678", [3,0], '.'), '12.345.678'); }); + QUnit.test('is_bin_size', function (assert) { + assert.expect(3); + + var is_bin_size = utils.is_bin_size; + + assert.strictEqual(is_bin_size('Cg=='), false); + assert.strictEqual(is_bin_size('2.5 Mb'), true); + // should also work for non-latin languages (e.g. russian) + assert.strictEqual(is_bin_size('64.2 Кб'), true); + }); + }); });
\ No newline at end of file diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 2458acf91f1..56249153c1f 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -715,7 +715,7 @@ class Page(models.Model): 'website_id': website.id, }) - return True + return url @api.multi def copy(self, default=None): diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js index b6d72df3d2a..a931cc057ef 100644 --- a/addons/website/static/src/js/menu/content.js +++ b/addons/website/static/src/js/menu/content.js @@ -205,7 +205,7 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ method: 'save_page_info', args: [[context.website_id], params], context: context, - }).then(function () { + }).then(function (url) { // If from page manager: reload url, if from page itself: go to // (possibly) new url if (self._getMainObject().model === 'website.page') { diff --git a/doc/cla/individual/true-datura.md b/doc/cla/individual/true-datura.md new file mode 100644 index 00000000000..e0d0faa8237 --- /dev/null +++ b/doc/cla/individual/true-datura.md @@ -0,0 +1,11 @@ +Ukraine, 2018-03-07 + +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, + +Demid Avramenko grrrr@protonmail.com https://github.com/true-datura diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py index 70e1d1b2d2c..3bfbe1b6bd4 100644 --- a/odoo/addons/test_new_api/models.py +++ b/odoo/addons/test_new_api/models.py @@ -338,6 +338,10 @@ class ComputeProtected(models.Model): for record in self: record.bar = record.foo + message = fields.Many2one('test_new_api.message') + message_name = fields.Text(related="message.body", related_sudo=False, string='Message Body') + message_currency = fields.Many2one(related="message.author", string='Message Author') + class ComputeInverse(models.Model): _name = 'test_new_api.compute.inverse' diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index a87006c76cb..7caf433a467 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -425,3 +425,32 @@ class TestOnChange(common.TransactionCase): 'size': email.size, })] ) + + def test_onchange_related(self): + value = { + 'message': 1, + 'message_name': False, + 'message_currency': 2, + } + field_onchange = { + 'message': '1', + 'message_name': None, + 'message_currency': None, + } + + onchange_result = { + 'message_name': 'Hey dude!', + 'message_currency': (1, 'Administrator') + } + + self.env.cache.invalidate() + Message = self.env['test_new_api.related'] + result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) + + self.assertEqual(result['value'], onchange_result) + + self.env.cache.invalidate() + Message = self.env(user=self.env.ref('base.user_demo').id)['test_new_api.related'] + result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) + + self.assertEqual(result['value'], onchange_result) diff --git a/odoo/models.py b/odoo/models.py index 3fdcaaf573e..89055976394 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -4999,15 +4999,16 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): done = set() # dummy assignment: trigger invalidations on the record - for name in todo: - if name == 'id': - continue - value = record[name] - field = self._fields[name] - if field.type == 'many2one' and field.delegate and not value: - # do not nullify all fields of parent record for new records - continue - record[name] = value + with env.do_in_onchange(): + for name in todo: + if name == 'id': + continue + value = record[name] + field = self._fields[name] + if field.type == 'many2one' and field.delegate and not value: + # do not nullify all fields of parent record for new records + continue + record[name] = value result = {} dirty = set() |
