summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-03-08 19:00:04 +0100
committerChristophe Simonis <chs@odoo.com>2018-03-08 19:00:04 +0100
commita0aa939d9b8440ae1223e103d70ae84455a1f9bc (patch)
tree129d0dd58abc42457ee4cbd8072d4059e2f24a2a
parent8f118ad5338878f399b02edba2440442e14cc1ab (diff)
parentfcb48b724152db876f6752560cce5a5d875e8f46 (diff)
[MERGE] forward port branch 11.0 up to fcb48b72415
-rw-r--r--addons/payment_ogone/controllers/main.py3
-rw-r--r--addons/payment_ogone/models/payment.py18
-rw-r--r--addons/portal/controllers/mail.py4
-rw-r--r--addons/project/models/project.py2
-rw-r--r--addons/purchase/tests/test_fifo_price.py4
-rw-r--r--addons/sale_timesheet/models/sale_order.py2
-rw-r--r--addons/stock/models/stock_quant.py10
-rw-r--r--addons/stock_dropshipping/tests/test_lifo_price.py4
-rw-r--r--addons/web/static/src/js/core/utils.js2
-rw-r--r--addons/web/static/src/js/views/basic/basic_renderer.js2
-rw-r--r--addons/web/static/tests/core/util_tests.js11
-rw-r--r--addons/website/models/website.py2
-rw-r--r--addons/website/static/src/js/menu/content.js2
-rw-r--r--doc/cla/individual/true-datura.md11
-rw-r--r--odoo/addons/test_new_api/models.py4
-rw-r--r--odoo/addons/test_new_api/tests/test_onchange.py29
-rw-r--r--odoo/models.py19
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()