diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index 8019a42688e..79e465f19c7 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -1075,7 +1075,7 @@ var ManualModel = StatementModel.extend({ return self._rpc({ model: 'account.move.line', method: 'get_data_for_manual_reconciliation', - args: ['account', model.account_ids || self.account_ids], + args: ['account', context.account_ids || self.account_ids], context: context, }) .then(function (result) { diff --git a/addons/payment_ogone/tests/test_ogone.py b/addons/payment_ogone/tests/test_ogone.py index b27e7a3c4ce..76215ebf72e 100644 --- a/addons/payment_ogone/tests/test_ogone.py +++ b/addons/payment_ogone/tests/test_ogone.py @@ -175,7 +175,4 @@ class OgonePayment(PaymentAcquirerCommon): 'number': '4000000000000002', 'brand': 'VISA'}) - # check an alias is set, containing at least OPENERP - self.assertIn('OPENERP', tx.partner_reference, 'ogone: wrong partner reference after creating an alias') - res = tx.ogone_s2s_execute({}) diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index 53bd6bd2455..f06b72461f9 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -167,8 +167,6 @@ class TxSips(models.Model): # check what is bought if float_compare(float(data.get('amount', '0.0')) / 100, self.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % self.amount)) - if self.partner_reference and data.get('customerId') != self.partner_reference: - invalid_parameters.append(('customerId', data.get('customerId'), self.partner_reference)) return invalid_parameters diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index db75edbe558..062825dc428 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -2207,6 +2207,8 @@ exports.Order = Backbone.Model.extend({ initialize_validation_date: function () { this.validation_date = new Date(); + this.formatted_validation_date = field_utils.format.datetime( + moment(this.validation_date), {}, {timezone: false}); }, set_tip: function(tip) { diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml index abe9c5b6703..84648f58eff 100644 --- a/addons/point_of_sale/static/src/xml/pos.xml +++ b/addons/point_of_sale/static/src/xml/pos.xml @@ -1444,7 +1444,7 @@
-
+


diff --git a/addons/web/static/src/js/chrome/view_manager.js b/addons/web/static/src/js/chrome/view_manager.js index 03eb2da27d8..c19fd8ab3e2 100644 --- a/addons/web/static/src/js/chrome/view_manager.js +++ b/addons/web/static/src/js/chrome/view_manager.js @@ -26,7 +26,7 @@ var ViewManager = Widget.extend(ControlPanelMixin, { search: function(event) { var d = event.data; _.extend(this.env, this._process_search_data(d.domains, d.contexts, d.groupbys)); - this.active_view.controller.reload(_.extend({}, this.env)); + this.active_view.controller.reload(_.extend({offset: 0}, this.env)); }, add_filter: '_onAddFilter', switch_view: function(event) { diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 5681be3262a..7e6a330120e 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -2098,8 +2098,9 @@ var FieldDomain = AbstractField.extend({ "click .o_field_domain_dialog_button": "_onDialogEditButtonClick", }), custom_events: _.extend({}, AbstractField.prototype.custom_events, { - "domain_changed": "_onDomainSelectorValueChange", - "domain_selected": "_onDomainSelectorDialogValueChange", + domain_changed: "_onDomainSelectorValueChange", + domain_selected: "_onDomainSelectorDialogValueChange", + open_record: "_onOpenRecord", }), /** * @constructor @@ -2280,6 +2281,15 @@ var FieldDomain = AbstractField.extend({ _onDomainSelectorDialogValueChange: function (e) { this._setValue(Domain.prototype.arrayToString(e.data.domain)); }, + /** + * Stops the propagation of the 'open_record' event, as we don't want the + * user to be able to open records from the list opened in a dialog. + * + * @param {OdooEvent} event + */ + _onOpenRecord: function (event) { + event.stopPropagation(); + }, }); /** diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js index 556a9919336..594a4507963 100644 --- a/addons/web/static/src/js/views/abstract_view.js +++ b/addons/web/static/src/js/views/abstract_view.js @@ -228,7 +228,7 @@ var AbstractView = Class.extend({ attrs.limit = attrs.mode === "tree" ? 80 : 40; - if (attrs.Widget.prototype.useSubview && !(attrs.invisible && JSON.parse(attrs.invisible)) && !attrs.views[attrs.mode]) { + if (attrs.Widget.prototype.useSubview && !attrs.__no_fetch && !attrs.views[attrs.mode]) { var context = {}; var regex = /'([a-z]*_view_ref)' *: *'(.*?)'/g; var matches; diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 0bd3c263666..e1a834b2c18 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -510,6 +510,7 @@ var FormController = BasicController.extend({ * @param {OdooEvent} event */ _onToggleColumnOrder: function (event) { + event.stopPropagation(); this.model.setSort(event.data.id, event.data.name); var field = event.data.field; var state = this.model.get(this.handle); diff --git a/addons/web/static/src/less/form_view_extra.less b/addons/web/static/src/less/form_view_extra.less index 11dd9961bef..99903a30db0 100644 --- a/addons/web/static/src/less/form_view_extra.less +++ b/addons/web/static/src/less/form_view_extra.less @@ -97,6 +97,18 @@ vertical-align: middle; } } + + &.o_full { + position: relative; + .o_button_more { + padding: 0 10px; + } + .o_dropdown_more { + .o-position-absolute(@top: 100%, @right: 0); + min-width: 0; + padding: 0px; + } + } } // Avatar diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 94fb0c4630c..9d0d0807199 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -3955,6 +3955,46 @@ QUnit.module('basic_fields', { form.destroy(); }); + + QUnit.test('basic domain field: show the selection', function (assert) { + assert.expect(2); + + this.data.partner.records[0].foo = "[]"; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: + '
' + + '' + + '' + + '' + + '' + + '' + + '
', + archs: { + 'partner_type,false,list': '', + 'partner_type,false,search': '', + }, + res_id: 1, + }); + + assert.equal(form.$(".o_domain_show_selection_button").text().trim().substr(0, 2), "2 ", + "selection should contain 2 records"); + + // open the selection + form.$(".o_domain_show_selection_button").click(); + assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2, + "should have open a list view with 2 records in a dialog"); + + // click on a record -> should not open the record + // we don't actually check that it doesn't open the record because even + // if it tries to, it will crash as we don't define an arch in this test + $('.modal .o_list_view .o_data_row:first .o_data_cell').click(); + + form.destroy(); + }); }); }); }); diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 5b559529371..330307195d0 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -947,8 +947,7 @@ var MockServer = Class.extend({ return $.when(this.data[args.model][args.method](args.args, args.kwargs)); } - console.error("Unimplemented route", route, args); - return $.when(); + throw new Error("Unimplemented route: " + route); }, /** * helper function: traverse a tree and apply the function f to each of its diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 4ac4213f378..716e581b44a 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -213,7 +213,7 @@ QUnit.module('Views', { }); QUnit.test('invisible fields are properly hidden', function (assert) { - assert.expect(3); + assert.expect(4); var form = createView({ View: FormView, @@ -226,6 +226,10 @@ QUnit.module('Views', { '' + '' + '' + + // x2many field without inline view: as it is always invisible, the view + // should not be fetched. we don't specify any view in this test, so if it + // ever tries to fetch it, it will crash, indicating that this is wrong. + '' + '' + '', res_id: 1, @@ -237,6 +241,8 @@ QUnit.module('Views', { "should not contain span with field value"); assert.strictEqual(form.$('.o_field_widget.o_invisible_modifier:contains(0.4)').length, 1, "field qux should be invisible"); + assert.ok(form.$('.o_field_widget[name=p]').hasClass('o_invisible_modifier'), + "field p should be invisible"); form.destroy(); }); @@ -5845,6 +5851,46 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('can toggle column in x2many in sub form view', function (assert) { + assert.expect(2); + + this.data.partner.records[2].p = [1,2]; + this.data.partner.fields.foo.sortable = true; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '', + res_id: 1, + mockRPC: function (route, args) { + if (route === '/web/dataset/call_kw/partner/get_formview_id') { + return $.when(false); + } + return this._super.apply(this, arguments); + }, + archs: { + 'partner,false,form': '
' + + '' + + '' + + '' + + '' + + '' + + '
', + }, + viewOptions: {mode: 'edit'}, + }); + form.$('.o_external_button').click(); + assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip", + "table has some initial order"); + + $('.modal-body .o_form_view .o_list_view th').click(); + assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop", + "table is now sorted"); + form.destroy(); + }); + QUnit.test('rainbowman attributes correctly passed on button click', function (assert) { assert.expect(1); diff --git a/addons/website_theme_install/static/src/less/website_theme_install.less b/addons/website_theme_install/static/src/less/website_theme_install.less index f72d98eb4f0..775b5761dea 100644 --- a/addons/website_theme_install/static/src/less/website_theme_install.less +++ b/addons/website_theme_install/static/src/less/website_theme_install.less @@ -6,9 +6,11 @@ /// Un-grouped Layout (default) &.o_kanban_ungrouped { .o-justify-content(space-between); + margin: 0 0 0 (@o-kanban-record-margin - 2 * @grid-gutter-width); - @media (min-width: @screen-md-min) { - margin: 0 -@grid-gutter-width; + @media (max-width: @screen-xs-max) { + padding-left: @odoo-horizontal-padding - @o-kanban-record-margin; + padding-right: @odoo-horizontal-padding; } .o_kanban_record { @@ -17,8 +19,7 @@ } .o_kanban_record { - margin-left: @grid-gutter-width; - margin-right: @grid-gutter-width; + margin-left: @grid-gutter-width * 2; padding: 0; box-shadow: none; background: none; diff --git a/odoo-bin b/odoo-bin index 535ea47f60f..fae9bf233b6 100755 --- a/odoo-bin +++ b/odoo-bin @@ -2,7 +2,6 @@ # set server timezone in UTC before time module imported __import__('os').environ['TZ'] = 'UTC' -__import__('pkg_resources').declare_namespace('odoo.addons') import odoo if __name__ == "__main__": diff --git a/odoo/__init__.py b/odoo/__init__.py index 3c3b14fdadc..2814706b57a 100644 --- a/odoo/__init__.py +++ b/odoo/__init__.py @@ -3,6 +3,12 @@ """ OpenERP core library.""" +#---------------------------------------------------------- +# odoo must be a namespace package for odoo.addons to become one too +# https://packaging.python.org/guides/packaging-namespace-packages/ +#---------------------------------------------------------- +__path__ = __import__('pkgutil').extend_path(__path__, __name__) + #---------------------------------------------------------- # Running mode flags (gevent, prefork) #---------------------------------------------------------- diff --git a/odoo/addons/__init__.py b/odoo/addons/__init__.py index d3a3e7e9ba2..c0058937588 100644 --- a/odoo/addons/__init__.py +++ b/odoo/addons/__init__.py @@ -14,4 +14,7 @@ This module also conveniently reexports some symbols from odoo.modules. Importing them from here is deprecated. """ -__import__('pkg_resources').declare_namespace(__name__) +# make odoo.addons a namespace package, while keeping this __init__.py +# present, for python 2 compatibility +# https://packaging.python.org/guides/packaging-namespace-packages/ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/setup/odoo b/setup/odoo index 535ea47f60f..fae9bf233b6 100644 --- a/setup/odoo +++ b/setup/odoo @@ -2,7 +2,6 @@ # set server timezone in UTC before time module imported __import__('os').environ['TZ'] = 'UTC' -__import__('pkg_resources').declare_namespace('odoo.addons') import odoo if __name__ == "__main__":