diff --git a/addons/lunch/static/src/js/lunch_kanban_controller.js b/addons/lunch/static/src/js/lunch_kanban_controller.js index 8055f876d2e..5545d926be3 100644 --- a/addons/lunch/static/src/js/lunch_kanban_controller.js +++ b/addons/lunch/static/src/js/lunch_kanban_controller.js @@ -18,11 +18,9 @@ var LunchKanbanController = KanbanController.extend({ add_product: '_onAddProduct', change_location: '_onLocationChanged', change_user: '_onUserChanged', - edit_order: '_onEditOrder', open_wizard: '_onOpenWizard', order_now: '_onOrderNow', remove_product: '_onRemoveProduct', - save_order: '_onSaveOrder', unlink_order: '_onUnlinkOrder', }), @@ -69,7 +67,23 @@ var LunchKanbanController = KanbanController.extend({ }, }).then(function (data) { self.widgetData = data; - self.model._updateLocation(data.user_location[0]); + return self.model._updateLocation(data.user_location[0]); + }); + }, + /** + * Renders and appends the lunch banner widget. + * + * @private + */ + _renderLunchKanbanWidget: function () { + var self = this; + if (this.widget) { + this.widget.destroy(); + } + this.widgetData.wallet = parseFloat(this.widgetData.wallet).toFixed(2); + this.widget = new LunchKanbanWidget(this, _.extend(this.widgetData, {edit: this.editMode})); + return this.widget.appendTo(document.createDocumentFragment()).then(function () { + self.$('.o_lunch_kanban').prepend(self.widget.$el); }); }, _showPaymentDialog: function (title) { @@ -91,19 +105,8 @@ var LunchKanbanController = KanbanController.extend({ * @private */ _update: function () { - var self = this; - - var def = this._fetchWidgetData().then(function () { - if (self.widget) { - self.widget.destroy(); - } - self.widgetData.wallet = parseFloat(self.widgetData.wallet).toFixed(2); - self.widget = new LunchKanbanWidget(self, _.extend(self.widgetData, {edit: self.editMode})); - return self.widget.appendTo(document.createDocumentFragment()).then(function () { - self.$('.o_lunch_kanban').prepend(self.widget.$el); - }); - }); - return $.when(def, this._super.apply(self, arguments)); + var def = this._fetchWidgetData().then(this._renderLunchKanbanWidget.bind(this)); + return $.when(def, this._super.apply(this, arguments)); }, /** * Override to add the location domain (coming from the lunchKanbanWidget) @@ -134,12 +137,6 @@ var LunchKanbanController = KanbanController.extend({ self.reload(); }); }, - _onEditOrder: function (ev) { - ev.stopPropagation(); - - this.editMode = true; - this.reload(); - }, _onLocationChanged: function (ev) { var self = this; @@ -208,12 +205,6 @@ var LunchKanbanController = KanbanController.extend({ self.reload(); }); }, - _onSaveOrder: function (ev) { - ev.stopPropagation(); - - this.editMode = false; - this.reload(); - }, _onUserChanged: function (ev) { ev.stopPropagation(); diff --git a/addons/lunch/static/src/js/lunch_kanban_mobile.js b/addons/lunch/static/src/js/lunch_kanban_mobile.js new file mode 100644 index 00000000000..eddd22ac351 --- /dev/null +++ b/addons/lunch/static/src/js/lunch_kanban_mobile.js @@ -0,0 +1,74 @@ +odoo.define('lunch.LunchKanbanMobile', function (require) { +"use strict"; + +var config = require('web.config'); +var LunchKanbanWidget = require('lunch.LunchKanbanWidget'); +var LunchKanbanController = require('lunch.LunchKanbanController'); + +if (!config.device.isMobile) { + return; +} + +LunchKanbanWidget.include({ + template: "LunchKanbanWidgetMobile", + + /** + * Override to set the toggle state allowing initially open it. + * + * @override + */ + init: function (parent, params) { + this._super.apply(this, arguments); + this.keepOpen = params.keepOpen || undefined; + }, +}); + +LunchKanbanController.include({ + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + this.openWidget = false; + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Override to add the widget's toggle state to its data. + * + * @override + * @private + */ + _renderLunchKanbanWidget: function () { + this.widgetData.keepOpen = this.openWidget; + this.openWidget = false; + return this._super.apply(this, arguments); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + * @private + */ + _onAddProduct: function () { + this.openWidget = true; + this._super.apply(this, arguments); + }, + + /** + * @override + * @private + */ + _onRemoveProduct: function () { + this.openWidget = true; + this._super.apply(this, arguments); + }, +}); + +}); diff --git a/addons/lunch/static/src/js/lunch_kanban_record.js b/addons/lunch/static/src/js/lunch_kanban_record.js index a0d60588fae..ce9272b34f0 100644 --- a/addons/lunch/static/src/js/lunch_kanban_record.js +++ b/addons/lunch/static/src/js/lunch_kanban_record.js @@ -1,22 +1,36 @@ odoo.define('lunch.LunchKanbanRecord', function (require) { -"use strict"; + "use strict"; -/** - * This file defines the KanbanRecord for the Lunch Kanban view. - */ + /** + * This file defines the KanbanRecord for the Lunch Kanban view. + */ -var KanbanRecord = require('web.KanbanRecord'); + var KanbanRecord = require('web.KanbanRecord'); -var LunchKanbanRecord = KanbanRecord.extend({ - _onGlobalClick: function (ev) { - ev.preventDefault(); - // ignore clicks on oe_kanban_action elements - if (!$(ev.target).hasClass('oe_kanban_action')) { - this.trigger_up('open_wizard', {productId: this.recordData.product_id}); - } - }, -}); + var LunchKanbanRecord = KanbanRecord.extend({ + events: _.extend({}, KanbanRecord.prototype.events, { + 'click': '_onSelectRecord', + }), -return LunchKanbanRecord; + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- -}); + /** + * Open the add product wizard + * + * @private + * @param {MouseEvent} ev Click event + */ + _onSelectRecord: function (ev) { + ev.preventDefault(); + // ignore clicks on oe_kanban_action elements + if (!$(ev.target).hasClass('oe_kanban_action')) { + this.trigger_up('open_wizard', {productId: this.recordData.product_id}); + } + }, + }); + + return LunchKanbanRecord; + + }); diff --git a/addons/lunch/static/src/js/lunch_kanban_view.js b/addons/lunch/static/src/js/lunch_kanban_view.js index 72b30634e87..a0cd6d3f3e0 100644 --- a/addons/lunch/static/src/js/lunch_kanban_view.js +++ b/addons/lunch/static/src/js/lunch_kanban_view.js @@ -5,19 +5,12 @@ var LunchKanbanController = require('lunch.LunchKanbanController'); var LunchKanbanModel = require('lunch.LunchKanbanModel'); var LunchKanbanRenderer = require('lunch.LunchKanbanRenderer'); -var config = require('web.config'); var core = require('web.core'); var KanbanView = require('web.KanbanView'); var view_registry = require('web.view_registry'); var _lt = core._lt; -if (config.device.isMobile) { - // use the classical KanbanView in mobile - view_registry.add('lunch_kanban', KanbanView); - return; -} - var LunchKanbanView = KanbanView.extend({ config: _.extend({}, KanbanView.prototype.config, { Controller: LunchKanbanController, diff --git a/addons/lunch/static/src/js/lunch_kanban_widget.js b/addons/lunch/static/src/js/lunch_kanban_widget.js index 73721c6def1..7bad4168b06 100644 --- a/addons/lunch/static/src/js/lunch_kanban_widget.js +++ b/addons/lunch/static/src/js/lunch_kanban_widget.js @@ -23,11 +23,9 @@ var LunchKanbanWidget = Widget.extend({ field_changed: '_onFieldChanged', }, events: { - 'click .o_add_money': '_onAddMoney', 'click .o_add_product': '_onAddProduct', 'click .o_lunch_widget_order_button': '_onOrderNow', 'click .o_remove_product': '_onRemoveProduct', - 'click .o_lunch_widget_save': '_onSaveOrder', 'click .o_lunch_widget_unlink': '_onUnlinkOrder', 'click .o_lunch_open_wizard': '_onLunchOpenWizard', }, @@ -124,11 +122,6 @@ var LunchKanbanWidget = Widget.extend({ // Handlers //-------------------------------------------------------------------------- - _onAddMoney: function (ev) { - ev.preventDefault(); - ev.stopPropagation(); - this.trigger_up('add_money', {}); - }, _onAddProduct: function (ev) { ev.preventDefault(); ev.stopPropagation(); @@ -163,12 +156,6 @@ var LunchKanbanWidget = Widget.extend({ this.trigger_up('remove_product', {lineId: $(ev.currentTarget).data('id')}); }, - _onSaveOrder: function (ev) { - ev.preventDefault(); - ev.stopPropagation(); - - this.trigger_up('save_order', {}); - }, _onUnlinkOrder: function (ev) { ev.preventDefault(); ev.stopPropagation(); diff --git a/addons/lunch/static/src/js/lunch_payment_dialog.js b/addons/lunch/static/src/js/lunch_payment_dialog.js index 00e49299189..ae624403f12 100644 --- a/addons/lunch/static/src/js/lunch_payment_dialog.js +++ b/addons/lunch/static/src/js/lunch_payment_dialog.js @@ -1,19 +1,15 @@ odoo.define('lunch.LunchPaymentDialog', function (require) { "use strict"; -var core = require('web.core'); var Dialog = require('web.Dialog'); -var qweb = core.qweb; - var LunchPaymentDialog = Dialog.extend({ template: 'lunch.LunchPaymentDialog', init: function (parent, options) { - var self = this; this._super.apply(this, arguments); - options = (options || {}); + options = options || {}; this.message = options.message || ''; }, diff --git a/addons/lunch/static/src/scss/lunch_kanban.scss b/addons/lunch/static/src/scss/lunch_kanban.scss index 7c50ae36358..51acfd2b3f8 100644 --- a/addons/lunch/static/src/scss/lunch_kanban.scss +++ b/addons/lunch/static/src/scss/lunch_kanban.scss @@ -6,6 +6,8 @@ height: 100%; .o_lunch_kanban_banner { flex: 0 0 auto; + border-bottom: 1px solid #CED4DA; + background-color: white; } .o_kanban_view { flex: 1 1 100%; @@ -19,52 +21,47 @@ } .o_lunch_widget { - display: flex; - border-bottom: 1px solid #CED4DA; - background-color: white; min-height: 90px; max-height: 33vh; overflow-y: auto; - .o_lunch_widget_info { - padding: 5px 12px; - margin: 4px 8px; - width: 300px; - flex: 1 1 auto; - overflow-y: auto; - - .o_lunch_ordered { - color: white; - background-color: #F0D970; - padding: 1px 3px; - border-radius: .25em; + .o_lunch_widget_info.card { + &, .card-title, .card-body { + color: $o-main-text-color; + background-color: inherit !important; } - .o_lunch_confirmed { - color: white; - background-color: #00BA4E; - padding: 1px 3px; - border-radius: .25em; - } - - .o_lunch_widget_title { + .card-title { font-weight: bold; - font-size: initial; + margin-bottom: 0; } - .o_lunch_widget_order_button { - display: block; - width: 100%; - margin-bottom: 4px; - margin-top: 12px; + .card-body { + padding: 0.5rem 1rem; } - .o_lunch_open_wizard { - cursor: pointer; - &:hover { - font-weight: bolder; + .btn-link { + padding: 0; + &.o_lunch_open_wizard { + color: $o-main-text-color; + font-weight: normal; } } } } } + +@include media-breakpoint-down(sm) { + .o_lunch_kanban { + details summary { + // Hide the caret. For details see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary + list-style-type: none; + &::-webkit-details-marker { + display: none + } + } + .o_lunch_widget { + max-height: 100% + } + } +} diff --git a/addons/lunch/static/src/xml/lunch_kanban.xml b/addons/lunch/static/src/xml/lunch_kanban.xml index 62a2edd2900..3b3b319ce95 100644 --- a/addons/lunch/static/src/xml/lunch_kanban.xml +++ b/addons/lunch/static/src/xml/lunch_kanban.xml @@ -1,84 +1,88 @@ -
-
-
-
- -
-
-
-
-
- Your Account - - - - +
+
+
+
+
+ +
+
+
+
+
+
+ Your Account + + + + +
+
-
+
- + - + -
-
- Your order - -
-
-
- -
+
-
-
- Total -
-
+
+

+ Total -

+ +
-
@@ -89,7 +93,7 @@
- + ctx.value = _.str.sprintf('%.2f', parseFloat(ctx.value)); @@ -104,9 +108,23 @@ - +
+ + +
+ + + Your cart + ( + + + ) + + +
+
diff --git a/addons/lunch/static/tests/lunch_kanban_mobile_tests.js b/addons/lunch/static/tests/lunch_kanban_mobile_tests.js new file mode 100644 index 00000000000..216d830bb47 --- /dev/null +++ b/addons/lunch/static/tests/lunch_kanban_mobile_tests.js @@ -0,0 +1,208 @@ +odoo.define('lunch.lunchKanbanMobileTests', function (require) { +"use strict"; + +const LunchKanbanView = require('lunch.LunchKanbanView'); + +const testUtils = require('web.test_utils'); +const {createLunchKanbanView, mockLunchRPC} = require('lunch.test_utils'); + +QUnit.module('Views'); + +QUnit.module('LunchKanbanView Mobile', { + beforeEach() { + const PORTAL_GROUP_ID = 1234; + + this.data = { + 'product': { + fields: { + is_available_at: {string: 'Product Availability', type: 'many2one', relation: 'lunch.location'}, + category_id: {string: 'Product Category', type: 'many2one', relation: 'lunch.product.category'}, + supplier_id: {string: 'Vendor', type: 'many2one', relation: 'lunch.supplier'}, + }, + records: [ + {id: 1, name: 'Tuna sandwich', is_available_at: 1}, + ], + }, + 'lunch.order': { + fields: {}, + update_quantity() { + return $.when(); + }, + }, + 'ir.model.data': { + fields: {}, + xmlid_to_res_id() { + return $.when(PORTAL_GROUP_ID); + }, + }, + 'lunch.location': { + fields: { + name: {string: 'Name', type: 'char'}, + }, + records: [ + {id: 1, name: "Office 1"}, + {id: 2, name: "Office 2"}, + ], + }, + }; + this.regularInfos = { + user_location: [2, "Office 2"], + }; + }, +}, function () { + QUnit.test('basic rendering', function (assert) { + assert.expect(9); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + assert.containsOnce(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', + "should have 1 records in the renderer"); + + // check view layout + assert.containsOnce(kanban, '.o_content > div', + "should have 1 column"); + assert.containsNone(kanban, '.o_content > div.o_search_panel', + "shouldn't have a 'lunch filters' column"); + assert.containsOnce(kanban, '.o_content > .o_lunch_kanban', + "should have a 'kanban lunch wrapper' column"); + assert.containsOnce(kanban, '.o_lunch_kanban > .o_kanban_view', + "should have a 'classical kanban view' column"); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_lunch_kanban_view', + "should have classname 'o_lunch_kanban_view'"); + assert.containsOnce($('.o_lunch_kanban'), '> details', + "should have a 'lunch kanban' details/summary discolure panel"); + assert.hasClass($('.o_lunch_kanban > details'), 'fixed-bottom', + "should have classname 'fixed-bottom'"); + assert.isNotVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + "shouldn't have a visible 'lunch kanban' banner"); + + kanban.destroy(); + }); + + QUnit.module('LunchKanbanWidget', function () { + QUnit.test('toggle', function (assert) { + assert.expect(6); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + total: "3.00", + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $details = $('.o_lunch_kanban > details'); + assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + "shouldn't have a visible 'lunch kanban' banner"); + assert.isVisible($details.find('> summary'), + "should hava a visible cart toggle button"); + assert.containsOnce($details, '> summary:contains(Your cart)', + "should have 'Your cart' in the button text"); + assert.containsOnce($details, '> summary:contains(3.00)', + "should have '3.00' in the button text"); + + testUtils.dom.click($details.find('> summary')); + assert.isVisible($details.find('.o_lunch_kanban_banner'), + "should have a visible 'lunch kanban' banner"); + + testUtils.dom.click($details.find('> summary')); + assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + "shouldn't have a visible 'lunch kanban' banner"); + + kanban.destroy(); + }); + + QUnit.test('keep open when adding quantities', function (assert) { + assert.expect(6); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + lines: [ + { + id: 6, + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $details = $('.o_lunch_kanban > details'); + assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + "shouldn't have a visible 'lunch kanban' banner"); + assert.isVisible($details.find('> summary'), + "should hava a visible cart toggle button"); + + testUtils.dom.click($details.find('> summary')); + assert.isVisible($details.find('.o_lunch_kanban_banner'), + "should have a visible 'lunch kanban' banner"); + + const $widgetSecondColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1)'); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + let $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + + testUtils.dom.click($firstLine.find('button.o_add_product')); + assert.isVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + "add quantity should keep 'lunch kanban' banner open"); + + $firstLine = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1) .o_lunch_widget_lines > li:first'); + + testUtils.dom.click($firstLine.find('button.o_remove_product')); + assert.isVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + "remove quantity should keep 'lunch kanban' banner open"); + + kanban.destroy(); + }); + }); +}); + +}); diff --git a/addons/lunch/static/tests/lunch_kanban_tests.js b/addons/lunch/static/tests/lunch_kanban_tests.js new file mode 100644 index 00000000000..571b11ed52e --- /dev/null +++ b/addons/lunch/static/tests/lunch_kanban_tests.js @@ -0,0 +1,821 @@ +odoo.define('lunch.lunchKanbanTests', function (require) { +"use strict"; + +const LunchKanbanView = require('lunch.LunchKanbanView'); + +const testUtils = require('web.test_utils'); +const {createLunchKanbanView, mockLunchRPC} = require('lunch.test_utils'); + +QUnit.module('Views'); + +QUnit.module('LunchKanbanView', { + beforeEach() { + const PORTAL_GROUP_ID = 1234; + + this.data = { + 'product': { + fields: { + is_available_at: {string: 'Product Availability', type: 'many2one', relation: 'lunch.location'}, + category_id: {string: 'Product Category', type: 'many2one', relation: 'lunch.product.category'}, + supplier_id: {string: 'Vendor', type: 'many2one', relation: 'lunch.supplier'}, + }, + records: [ + {id: 1, name: 'Tuna sandwich', is_available_at: 1}, + ], + }, + 'lunch.order': { + fields: {}, + update_quantity() { + return $.when(); + }, + }, + 'lunch.product.category': { + fields: {}, + records: [], + }, + 'lunch.supplier': { + fields: {}, + records: [], + }, + 'ir.model.data': { + fields: {}, + xmlid_to_res_id() { + return $.when(PORTAL_GROUP_ID); + }, + }, + 'lunch.location': { + fields: { + name: {string: 'Name', type: 'char'}, + }, + records: [ + {id: 1, name: "Office 1"}, + {id: 2, name: "Office 2"}, + ], + }, + 'res.users': { + fields: { + name: {string: 'Name', type: 'char'}, + groups_id: {string: 'Groups', type: 'many2many'}, + }, + records: [ + {id: 1, name: "Mitchell Admin", groups_id: []}, + {id: 2, name: "Marc Demo", groups_id: []}, + {id: 3, name: "Jean-Luc Portal", groups_id: [PORTAL_GROUP_ID]}, + ], + }, + }; + this.regularInfos = { + username: "Marc Demo", + wallet: 36.5, + is_manager: false, + currency: { + symbol: "\u20ac", + position: "after" + }, + user_location: [2, "Office 2"], + }; + this.managerInfos = { + username: "Mitchell Admin", + wallet: 47.6, + is_manager: true, + currency: { + symbol: "\u20ac", + position: "after" + }, + user_location: [2, "Office 2"], + }; + }, +}, function () { + QUnit.test('basic rendering', function (assert) { + assert.expect(7); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + assert.containsOnce(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', + "should have 1 records in the renderer"); + + // check view layout + assert.containsN(kanban, '.o_content > div', 2, + "should have 2 columns"); + assert.containsOnce(kanban, '.o_content > div.o_search_panel', + "should have a 'lunch filters' column"); + assert.containsOnce(kanban, '.o_content > .o_lunch_kanban', + "should have a 'kanban lunch wrapper' column"); + assert.containsOnce(kanban, '.o_lunch_kanban > .o_kanban_view', + "should have a 'classical kanban view' column"); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_lunch_kanban_view', + "should have classname 'o_lunch_kanban_view'"); + assert.containsOnce(kanban, '.o_lunch_kanban > .o_lunch_kanban_banner', + "should have a 'lunch kanban' banner"); + + kanban.destroy(); + }); + + QUnit.module('LunchKanbanWidget', function () { + + QUnit.test('empty cart', function (assert) { + assert.expect(3); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsN($kanbanWidget, '> .o_lunch_widget_info', 3, + "should have 3 columns"); + assert.isVisible($kanbanWidget.find('> .o_lunch_widget_info:first'), + "should have the first column visible"); + assert.strictEqual($kanbanWidget.find('> .o_lunch_widget_info:not(:first)').html().trim(), "", + "all columns but the first should be empty"); + + kanban.destroy(); + }); + + QUnit.test('non-empty cart', function (assert) { + assert.expect(17); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + total: "3.00", + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsN($kanbanWidget, '> .o_lunch_widget_info', 3, + "should have 3 columns"); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:eq(1)', + "should have a second column"); + + const $widgetSecondColumn = $kanbanWidget.find('.o_lunch_widget_info:eq(1)'); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_unlink', + "should have a button to clear the order"); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + const $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + assert.containsOnce($firstLine, 'button.o_remove_product', + "should have a button to remove a product quantity on each line"); + assert.containsOnce($firstLine, 'button.o_add_product', + "should have a button to add a product quantity on each line"); + assert.containsOnce($firstLine, '.o_lunch_product_quantity > :eq(1)', + "should have the line's quantity"); + assert.strictEqual($firstLine.find('.o_lunch_product_quantity > :eq(1)').text().trim(), "1", + "should have 1 as the line's quantity"); + assert.containsOnce($firstLine, '.o_lunch_open_wizard', + "should have the line's product name to open the wizard"); + assert.strictEqual($firstLine.find('.o_lunch_open_wizard').text().trim(), "Tuna sandwich", + "should have 'Tuna sandwich' as the line's product name"); + assert.containsOnce($firstLine, '.o_field_monetary', + "should have the line's amount"); + assert.strictEqual($firstLine.find('.o_field_monetary').text().trim(), "3.00€", + "should have '3.00€' as the line's amount"); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:eq(2)', + "should have a third column"); + + const $widgetThirdColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(2)'); + + assert.containsOnce($widgetThirdColumn, '.o_field_monetary', + "should have an account balance"); + assert.strictEqual($widgetThirdColumn.find('.o_field_monetary').text().trim(), "3.00€", + "should have '3.00€' in the account balance"); + assert.containsOnce($widgetThirdColumn, '.o_lunch_widget_order_button', + "should have a button to validate the order"); + assert.strictEqual($widgetThirdColumn.find('.o_lunch_widget_order_button').text().trim(), "Order now", + "should have 'Order now' as the validate order button text"); + + kanban.destroy(); + }); + + QUnit.test('ordered cart', function (assert) { + assert.expect(15); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + raw_state: "ordered", + state: "Ordered", + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsN($kanbanWidget, '> .o_lunch_widget_info', 3, + "should have 3 columns"); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:eq(1)', + "should have a second column"); + + const $widgetSecondColumn = $kanbanWidget.find('.o_lunch_widget_info:eq(1)'); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_unlink', + "should have a button to clear the order"); + assert.containsOnce($widgetSecondColumn, '.badge.badge-warning.o_lunch_ordered', + "should have an ordered state badge"); + assert.strictEqual($widgetSecondColumn.find('.o_lunch_ordered').text().trim(), "Ordered", + "should have 'Ordered' in the state badge"); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + const $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + assert.containsOnce($firstLine, 'button.o_remove_product', + "should have a button to remove a product quantity on each line"); + assert.containsOnce($firstLine, 'button.o_add_product', + "should have a button to add a product quantity on each line"); + assert.containsOnce($firstLine, '.o_lunch_product_quantity > :eq(1)', + "should have the line's quantity"); + assert.strictEqual($firstLine.find('.o_lunch_product_quantity > :eq(1)').text().trim(), "1", + "should have 1 as the line's quantity"); + assert.containsOnce($firstLine, '.o_lunch_open_wizard', + "should have the line's product name to open the wizard"); + assert.strictEqual($firstLine.find('.o_lunch_open_wizard').text().trim(), "Tuna sandwich", + "should have 'Tuna sandwich' as the line's product name"); + assert.containsOnce($firstLine, '.o_field_monetary', + "should have the line's amount"); + assert.strictEqual($firstLine.find('.o_field_monetary').text().trim(), "3.00€", + "should have '3.00€' as the line's amount"); + + assert.strictEqual($kanbanWidget.find('> .o_lunch_widget_info:eq(2)').html().trim(), "", + "third column should be empty"); + + kanban.destroy(); + }); + + QUnit.test('confirmed cart', function (assert) { + assert.expect(15); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + raw_state: "confirmed", + state: "Received", + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsN($kanbanWidget, '> .o_lunch_widget_info', 3, + "should have 3 columns"); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:eq(1)', + "should have a second column"); + + const $widgetSecondColumn = $kanbanWidget.find('.o_lunch_widget_info:eq(1)'); + + assert.containsNone($widgetSecondColumn, '.o_lunch_widget_unlink', + "shouldn't have a button to clear the order"); + assert.containsOnce($widgetSecondColumn, '.badge.badge-success.o_lunch_confirmed', + "should have a confirmed state badge"); + assert.strictEqual($widgetSecondColumn.find('.o_lunch_confirmed').text().trim(), "Received", + "should have 'Received' in the state badge"); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + const $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + assert.containsNone($firstLine, 'button.o_remove_product', + "shouldn't have a button to remove a product quantity on each line"); + assert.containsNone($firstLine, 'button.o_add_product', + "shouldn't have a button to add a product quantity on each line"); + assert.containsOnce($firstLine, '.o_lunch_product_quantity', + "should have the line's quantity"); + assert.strictEqual($firstLine.find('.o_lunch_product_quantity').text().trim(), "1", + "should have 1 as the line's quantity"); + assert.containsOnce($firstLine, '.o_lunch_open_wizard', + "should have the line's product name to open the wizard"); + assert.strictEqual($firstLine.find('.o_lunch_open_wizard').text().trim(), "Tuna sandwich", + "should have 'Tuna sandwich' as the line's product name"); + assert.containsOnce($firstLine, '.o_field_monetary', + "should have the line's amount"); + assert.strictEqual($firstLine.find('.o_field_monetary').text().trim(), "3.00€", + "should have '3.00€' as the line's amount"); + + assert.strictEqual($kanbanWidget.find('> .o_lunch_widget_info:eq(2)').html().trim(), "", + "third column should be empty"); + + kanban.destroy(); + }); + + QUnit.test('regular user', function (assert) { + assert.expect(11); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:first', + "should have a first column"); + + const $widgetFirstColumn = $kanbanWidget.find('.o_lunch_widget_info:first'); + + assert.containsOnce($widgetFirstColumn, 'img.rounded-circle', + "should have a rounded avatar image"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_user_field', + "should have a user field"); + assert.containsNone($widgetFirstColumn, '.o_lunch_user_field > .o_field_widget', + "shouldn't have a field widget in the user field"); + assert.strictEqual($widgetFirstColumn.find('.o_lunch_user_field').text().trim(), "Marc Demo", + "should have 'Marc Demo' in the user field"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field', + "should have a location field"); + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field > .o_field_many2one[name="locations"]', + "should have a many2one in the location field"); + + testUtils.fields.many2one.clickOpenDropdown('locations'); + const $input = $widgetFirstColumn.find('.o_field_many2one[name="locations"] input'); + assert.containsN($input.autocomplete('widget'), 'li', 2, + "autocomplete dropdown should have 2 entries"); + assert.strictEqual($input.val(), "Office 2", + "locations input should have 'Office 2' as value"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field + div', + "should have an account balance"); + assert.strictEqual($widgetFirstColumn.find('.o_lunch_location_field + div .o_field_monetary').text().trim(), "36.50€", + "should have '36.50€' in the account balance"); + + kanban.destroy(); + }); + + QUnit.test('manager user', function (assert) { + assert.expect(12); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.managerInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $kanbanWidget = kanban.$('.o_lunch_widget'); + + assert.containsOnce($kanbanWidget, '.o_lunch_widget_info:first', + "should have a first column"); + + const $widgetFirstColumn = $kanbanWidget.find('.o_lunch_widget_info:first'); + + assert.containsOnce($widgetFirstColumn, 'img.rounded-circle', + "should have a rounded avatar image"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_user_field', + "should have a user field"); + assert.containsOnce($widgetFirstColumn, '.o_lunch_user_field > .o_field_many2one[name="users"]', + "shouldn't have a field widget in the user field"); + + testUtils.fields.many2one.clickOpenDropdown('users'); + const $userInput = $widgetFirstColumn.find('.o_field_many2one[name="users"] input'); + assert.containsN($userInput.autocomplete('widget'), 'li', 2, + "users autocomplete dropdown should have 2 entries"); + assert.strictEqual($userInput.val(), "Mitchell Admin", + "should have 'Mitchell Admin' as value in user field"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field', + "should have a location field"); + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field > .o_field_many2one[name="locations"]', + "should have a many2one in the location field"); + + testUtils.fields.many2one.clickOpenDropdown('locations'); + const $locationInput = $widgetFirstColumn.find('.o_field_many2one[name="locations"] input'); + assert.containsN($locationInput.autocomplete('widget'), 'li', 2, + "locations autocomplete dropdown should have 2 entries"); + assert.strictEqual($locationInput.val(), "Office 2", + "should have 'Office 2' as value"); + + assert.containsOnce($widgetFirstColumn, '.o_lunch_location_field + div', + "should have an account balance"); + assert.strictEqual($widgetFirstColumn.find('.o_lunch_location_field + div .o_field_monetary').text().trim(), "47.60€", + "should have '47.60€' in the account balance"); + + kanban.destroy(); + }); + + QUnit.test('add a product', function (assert) { + assert.expect(1); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + intercepts: { + do_action: function (ev) { + assert.deepEqual(ev.data.action, { + res_model: 'lunch.order.temp', + type: 'ir.actions.act_window', + views: [[false, 'form']], + target: 'new', + context: { + default_product_id: undefined, + line_id: false, + }, + }, + "should open the wizard"); + }, + }, + }); + + testUtils.dom.click(kanban.$('.o_kanban_record:first')); + + kanban.destroy(); + }); + + QUnit.test('add product quantity', function (assert) { + assert.expect(3); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: Object.assign({}, this.data, { + 'lunch.order': { + fields: {}, + update_quantity([lineIds, increment]) { + assert.deepEqual(lineIds, [6], "should have [6] as lineId to update quantity"); + assert.strictEqual(increment, 1, "should have +1 as increment to update quantity"); + return $.when(); + }, + }, + }), + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + lines: [ + { + id: 6, + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $widgetSecondColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1)'); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + const $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + + testUtils.dom.click($firstLine.find('button.o_add_product')); + + kanban.destroy(); + }); + + QUnit.test('remove product quantity', function (assert) { + assert.expect(3); + + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: Object.assign({}, this.data, { + 'lunch.order': { + fields: {}, + update_quantity([lineIds, increment]) { + assert.deepEqual(lineIds, [6], "should have [6] as lineId to update quantity"); + assert.strictEqual(increment, -1, "should have -1 as increment to update quantity"); + return $.when(); + }, + }, + }), + arch: ` + + + +
+
+
+
+ `, + mockRPC: mockLunchRPC({ + infos: Object.assign({}, this.regularInfos, { + lines: [ + { + id: 6, + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + quantity: 1.0, + }, + ], + }), + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + const $widgetSecondColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1)'); + + assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li', + "should have 1 order line"); + + const $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); + + testUtils.dom.click($firstLine.find('button.o_remove_product')); + + kanban.destroy(); + }); + + QUnit.test('clear order', function (assert) { + assert.expect(1); + + const self = this; + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: function (route) { + if (route.startsWith('/lunch')) { + if (route === '/lunch/trash') { + assert.ok('should perform clear order RPC call'); + return $.when(); + } + return mockLunchRPC({ + infos: Object.assign({}, self.regularInfos, { + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + }, + ], + }), + userLocation: self.data['lunch.location'].records[0].id, + }).apply(this, arguments); + } + return this._super.apply(this, arguments); + }, + }); + + const $widgetSecondColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1)'); + + testUtils.dom.click($widgetSecondColumn.find('button.o_lunch_widget_unlink')); + + kanban.destroy(); + }); + + QUnit.test('validate order: success', function (assert) { + assert.expect(1); + + const self = this; + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: function (route) { + if (route.startsWith('/lunch')) { + if (route === '/lunch/pay') { + assert.ok("should perform pay order RPC call"); + return $.when(true); + } + return mockLunchRPC({ + infos: Object.assign({}, self.regularInfos, { + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + }, + ], + }), + userLocation: self.data['lunch.location'].records[0].id, + }).apply(this, arguments); + } + return this._super.apply(this, arguments); + }, + }); + + const $widgetThirdColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(2)'); + + testUtils.dom.click($widgetThirdColumn.find('button.o_lunch_widget_order_button')); + + kanban.destroy(); + }); + + QUnit.test('validate order: failure', function (assert) { + assert.expect(5); + + const self = this; + const kanban = createLunchKanbanView({ + View: LunchKanbanView, + model: 'product', + data: this.data, + arch: ` + + + +
+
+
+
+ `, + mockRPC: function (route) { + if (route.startsWith('/lunch')) { + if (route === '/lunch/pay') { + assert.ok('should perform pay order RPC call'); + return $.when(false); + } + if (route === '/lunch/payment_message') { + assert.ok('should perform payment message RPC call'); + return $.when({ message: 'This is a payment message.'}); + } + return mockLunchRPC({ + infos: Object.assign({}, self.regularInfos, { + lines: [ + { + product: [1, "Tuna sandwich", "3.00"], + toppings: [], + }, + ], + }), + userLocation: self.data['lunch.location'].records[0].id, + }).apply(this, arguments); + } + return this._super.apply(this, arguments); + }, + }); + + const $widgetThirdColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(2)'); + + testUtils.dom.click($widgetThirdColumn.find('button.o_lunch_widget_order_button')); + + assert.containsOnce(document.body, '.modal', "should open a Dialog box"); + assert.strictEqual($('.modal-title').text().trim(), + "Not enough money in your wallet", "should have a Dialog's title"); + assert.strictEqual($('.modal-body').text().trim(), + "This is a payment message.", "should have a Dialog's message"); + + kanban.destroy(); + }); + + }); +}); + +}); diff --git a/addons/lunch/static/tests/lunch_test_utils.js b/addons/lunch/static/tests/lunch_test_utils.js new file mode 100644 index 00000000000..3c8b52d18e3 --- /dev/null +++ b/addons/lunch/static/tests/lunch_test_utils.js @@ -0,0 +1,58 @@ +odoo.define('lunch.test_utils', function (require) { +"use strict"; + +const AbstractStorageService = require('web.AbstractStorageService'); +const RamStorage = require('web.RamStorage'); +const {createView} = require('web.test_utils'); + +/** + * Helper to create a lunch kanban view with searchpanel + * + * @param {object} params + */ +function createLunchKanbanView(params) { + const archPieces = params.arch.split(''); + params.arch = ` + ${archPieces[0]} + + + + + ${archPieces[1]} + `; + if (!params.services || !params.services.local_storage) { + // the searchPanel uses the localStorage to store/retrieve default + // active category value + params.services = params.services || {}; + const RamStorageService = AbstractStorageService.extend({ + storage: new RamStorage(), + }); + params.services.local_storage = RamStorageService; + } + return createView(params); +} + +/** + * Helper to generate a mockRPC function for the mandatory lunch routes (prefixed by '/lunch') + * + * @param {object} infos + * @param {integer} userLocation + */ +function mockLunchRPC({infos, userLocation}) { + return function (route) { + if (route === '/lunch/infos') { + return $.when(infos); + } + if (route === '/lunch/user_location_get') { + return $.when(userLocation); + } + return this._super.apply(this, arguments); + }; +} + +return { + createLunchKanbanView, + mockLunchRPC, +}; + +}); diff --git a/addons/lunch/static/tests/test_lunch_kanban.js b/addons/lunch/static/tests/test_lunch_kanban.js deleted file mode 100644 index 020c3748150..00000000000 --- a/addons/lunch/static/tests/test_lunch_kanban.js +++ /dev/null @@ -1,259 +0,0 @@ -odoo.define('lunch.lunchKanbanTests', function (require) { -"use strict"; - -var LunchKanbanView = require('lunch.LunchKanbanView'); -var LunchKanbanWidget = require('lunch.LunchKanbanWidget'); -var testUtils = require('web.test_utils'); - -var createView = testUtils.createView; - -QUnit.module('Views', { - beforeEach: function () { - this.data = { - product: { - fields: { - id: {string: 'ID', type: 'integer'}, - is_available_at: {string: 'available_location_ids', type: 'integer'}, - }, - records: [ - {id: 1, name: 'Tuna sandwich', price: 3.0, is_available_at: 1}, - ] - }, - }; - }, -}, function () { - QUnit.module('LunchKanbanView'); - - QUnit.test('Simple rendering of LunchKanbanView', function (assert) { - assert.expect(7); - - var lunchKanban = createView({ - View: LunchKanbanView, - model: 'product', - data: this.data, - arch: '' + - '
' + - '
' + - '
', - mockRPC: function(route, args) { - if (route === '/lunch/infos') { - return $.when({ - order: 1, - wallet: 20, - username: 'Marc Demo', - userimage: '', - is_manager: false, - users: [ - {id: 1, name: 'Mitchell Admin'}, - {id: 2, name: 'Marc Demo'}, - ], - total: 7.4, - state: 'new', - lines: [ - {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4} - ], - alerts: [], - locations: ['hello', 'hallo'], - user_location: [1, 'hello'], - }); - } else if (route === '/lunch/user_location_get') { - return $.when(1); - } else if (route === '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id') { - return $.when(); - } else if (route.startsWith('data:image/png;base64,')) { - return $.when(); - } - return this._super(route, args); - }, - }); - - var $section = $(lunchKanban.$('.o_lunch_widget_info')[0]); - // username - assert.strictEqual($section.find('div:eq(1) div:eq(0)').text().trim(), 'Marc Demo', 'Username should have been Marc Demo'); - // your order section - $section = $(lunchKanban.$('.o_lunch_widget_info')[1]); - // only one line - assert.strictEqual($section.find('div:eq(2) div.d-flex').length, 1, 'There should be only one line'); - // quantity = 1 - assert.strictEqual($section.find('div:eq(2) div:eq(0) span:eq(0)').text().trim(), '1', 'The line should contain only one product'); - // buttons to remove and to add product - assert.strictEqual($section.find('.o_remove_product').length, 1, 'There should be a remove product button'); - assert.strictEqual($section.find('.o_add_product').length, 1, 'There should be a add product button'); - - $section = $(lunchKanban.$('.o_lunch_widget_info')[2]); - // total - assert.strictEqual($section.find('div:eq(0) div:eq(1)').text().trim(), '7.40', 'total should be of 7.40'); - // order now button - assert.strictEqual($section.find('button').length, 1, 'order now button should be available'); - - lunchKanban.destroy(); - }); - - QUnit.test('User interactions', function (assert) { - assert.expect(9); - - var state = 'new'; - - var lunchKanban = createView({ - View: LunchKanbanView, - model: 'product', - data: this.data, - arch: '' + - '
' + - '
' + - '
', - mockRPC: function(route, args) { - if (route === '/lunch/infos') { - return $.when({ - order: 1, - wallet: 20, - username: 'Marc Demo', - userimage: '', - is_manager: false, - users: [ - {id: 1, name: 'Mitchell Admin'}, - {id: 2, name: 'Marc Demo'}, - ], - total: 7.4, - raw_state: state, - state: 'New', - lines: [ - {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4} - ], - alerts: [], - locations: ['hello', 'hallo'], - user_location: [1, 'hello'], - }); - } else if (route === '/lunch/payment_message') { - return $.when({message: 'Hello'}); - } else if (route === '/lunch/pay') { - return $.when(true); - } else if (route === '/lunch/user_location_get') { - return $.when(1); - } else if (args.method === 'update_quantity') { - assert.step(args.args); - return $.when(); - } else if (route === '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id') { - return $.when(); - } else if (route.startsWith('data:image/png;base64,')) { - return $.when(); - } - return this._super(route, args); - }, - }); - - lunchKanban.$('.o_add_product').click(); - lunchKanban.$('.o_remove_product').click(); - - state = 'ordered'; - lunchKanban.$('.o_lunch_widget_order_button').click(); - // state is shown - assert.strictEqual(lunchKanban.$('.o_lunch_ordered').length, 1, 'state should be shown as ordered'); - // buttons - assert.strictEqual(lunchKanban.$('.o_remove_product').length, 1, 'button to remove product should be shown'); - assert.strictEqual(lunchKanban.$('.o_add_product').length, 1, 'button to add product should be shown'); - state = 'confirmed'; - lunchKanban.reload(); - // state is updated - assert.strictEqual(lunchKanban.$('.o_lunch_confirmed').length, 1, 'state should be shown as confirmed'); - // Buttons not shown anymore - assert.strictEqual(lunchKanban.$('.o_remove_product').length, 0, 'button to remove product should not be shown'); - assert.strictEqual(lunchKanban.$('.o_add_product').length, 0, 'button to add product should not be shown'); - - - assert.verifySteps([ - [[1], 1], - [[1], -1], - ]); - - lunchKanban.destroy(); - }); - - QUnit.test('Manager interactions', function (assert) { - assert.expect(1); - - var lunchKanban = createView({ - View: LunchKanbanView, - model: 'product', - data: this.data, - arch: '' + - '
' + - '
' + - '
', - mockRPC: function(route, args) { - if (route === '/lunch/infos') { - return $.when({ - order: 1, - wallet: 20, - username: 'Marc Demo', - userimage: '', - is_manager: true, - users: [ - {id: 1, name: 'Mitchell Admin'}, - {id: 2, name: 'Marc Demo'}, - ], - total: 7.4, - raw_state: 'new', - state: 'New', - lines: [ - {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4} - ], - alerts: [], - locations: ['hello', 'hallo'], - user_location: [1, 'hello'], - }); - } else if (route === '/lunch/user_location_get') { - return $.when(1); - } else if (route === '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id') { - return $.when(); - } else if (route.startsWith('data:image/png;base64,')) { - return $.when(); - } - return this._super(route, args); - }, - }); - - var select = lunchKanban.$('div.o_lunch_user_field div.o_field_widget.o_field_many2one'); - - assert.strictEqual(select.length, 1, 'There should be a user selection field'); - - lunchKanban.destroy(); - }); - - QUnit.module('LunchKanbanWidget'); - - QUnit.test('Rpc calls should be performed after the init()', function (assert) { - assert.expect(2); - - var parent = testUtils.createParent({}); - - var widget = new LunchKanbanWidget(parent, { - user_location: [1, 'hello'], - }); - - testUtils.mock.addMockEnvironment(widget, { - data: {}, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id') { - assert.ok('should perform xmlid_to_res_id RPC call in the willStart()'); - assert.deepEqual(args, { - args: [], - kwargs: { - xmlid: "base.group_portal", - }, - method: "xmlid_to_res_id", - model: "ir.model.data", - }, 'should have the right parameters for xmlid_to_res_id RPC call'); - return $.when(); - } - return this._super.apply(this, arguments); - }, - }); - - widget.appendTo($("#qunit-fixture")); - - parent.destroy(); - }); -}); - -}); diff --git a/addons/lunch/views/lunch_templates.xml b/addons/lunch/views/lunch_templates.xml index a076bbb2261..40c57da0b79 100644 --- a/addons/lunch/views/lunch_templates.xml +++ b/addons/lunch/views/lunch_templates.xml @@ -11,16 +11,25 @@ + + + diff --git a/addons/web/static/src/scss/search_view_mobile.scss b/addons/web/static/src/scss/search_view_mobile.scss index c3c264649ea..dd72aaae83b 100644 --- a/addons/web/static/src/scss/search_view_mobile.scss +++ b/addons/web/static/src/scss/search_view_mobile.scss @@ -7,7 +7,7 @@ padding: 0; width: 100%; background-color: white; - z-index: 1000; + z-index: $zindex-modal; overflow: auto; .o_mobile_search_header { height: 46px; @@ -89,7 +89,6 @@ right: 0; padding: 15px; font-size: 17px; - z-index: 1000; } } }