diff options
| author | Anh Thao Pham (pta) <pta@odoo.com> | 2020-03-18 07:29:31 +0000 |
|---|---|---|
| committer | Yannick Tivisse <yti@odoo.com> | 2020-04-30 11:40:39 +0000 |
| commit | 8b6b09fc26dc35f57a68584a668940e1d8bde1ff (patch) | |
| tree | 45a020f829e1a26b9743800af71219cd74559a5d | |
| parent | 918a5f2cc022994ee08bead25dd79072bf3fba87 (diff) | |
[IMP] lunch: add list view for lunch.product.report
- Move code from kanban view that is common with list view in common files
- Add action to add selected products to cart
- Add/update tests
closes odoo/odoo#47556
Taskid: 2160048
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
21 files changed, 822 insertions, 393 deletions
diff --git a/addons/lunch/__manifest__.py b/addons/lunch/__manifest__.py index 0bf568e7550..ab9729eed45 100644 --- a/addons/lunch/__manifest__.py +++ b/addons/lunch/__manifest__.py @@ -38,7 +38,7 @@ If you want to save your employees' time and avoid them to always have coins in 'data/ir_cron_data.xml' ], 'demo': ['data/lunch_demo.xml'], - 'qweb': ['static/src/xml/lunch_kanban.xml', ], + 'qweb': ['static/src/xml/lunch_templates.xml', ], 'installable': True, 'application': True, 'certificate': '001292377792581874189', diff --git a/addons/lunch/static/src/js/lunch_controller_common.js b/addons/lunch/static/src/js/lunch_controller_common.js new file mode 100644 index 00000000000..27ce66ec49c --- /dev/null +++ b/addons/lunch/static/src/js/lunch_controller_common.js @@ -0,0 +1,253 @@ +odoo.define('lunch.LunchControllerCommon', function (require) { +"use strict"; + +/** + * This file defines the common events and functions used by Controllers for the Lunch view. + */ + +var session = require('web.session'); +var core = require('web.core'); +var LunchWidget = require('lunch.LunchWidget'); +var LunchPaymentDialog = require('lunch.LunchPaymentDialog'); + +var _t = core._t; + +var LunchControllerCommon = { + custom_events: { + add_product: '_onAddProduct', + change_location: '_onLocationChanged', + change_user: '_onUserChanged', + open_wizard: '_onOpenWizard', + order_now: '_onOrderNow', + remove_product: '_onRemoveProduct', + unlink_order: '_onUnlinkOrder', + }, + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + this.userId = null; + this.editMode = false; + this.updated = false; + this.widgetData = null; + this.context = session.user_context; + this.archiveEnabled = false; + }, + /** + * @override + */ + start: function () { + // create a div inside o_content that will be used to wrap the lunch + // banner and renderer (this is required to get the desired + // layout with the searchPanel to the left) + var self = this; + this.$('.o_content').append($('<div>').addClass('o_lunch_content')); + return this._super.apply(this, arguments).then(function () { + self.$('.o_lunch_content').append(self.$('.o_lunch_view')); + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + _fetchPaymentInfo: function () { + return this._rpc({ + route: '/lunch/payment_message', + params: { + context: this.context, + }, + }); + }, + _fetchWidgetData: function () { + var self = this; + + return this._rpc({ + route: '/lunch/infos', + params: { + user_id: this.userId, + context: this.context, + }, + }).then(function (data) { + self.widgetData = data; + return self.model._updateLocation(data.user_location[0]); + }); + }, + /** + * Override to add the location domain (coming from the LunchWidget) + * to the searchDomain (coming from the controlPanel). + * + * @override + */ + _getViewDomain: async function () { + return this.model.getLocationDomain(); + }, + /** + * Renders and appends the lunch banner widget. + * + * @private + */ + _renderLunchWidget: function () { + var self = this; + var oldWidget = this.widget; + this.widgetData.wallet = parseFloat(this.widgetData.wallet).toFixed(2); + this.widget = new LunchWidget(this, _.extend(this.widgetData, {edit: this.editMode})); + return this.widget.appendTo(document.createDocumentFragment()).then(function () { + self.$('.o_lunch_content').prepend(self.widget.$el); + if (oldWidget) { + oldWidget.destroy(); + } + }); + }, + _showPaymentDialog: function (title) { + var self = this; + + title = title || ''; + + this._fetchPaymentInfo().then(function (data) { + var paymentDialog = new LunchPaymentDialog(self, _.extend(data, {title: title})); + paymentDialog.open(); + }); + }, + /** + * Override to fetch and display the lunch data. Because of the presence of + * the searchPanel, also wrap the lunch widget and the renderer into + * a div, to get the desired layout. + * + * @override + * @private + */ + _update: function () { + var def = this._fetchWidgetData().then(this._renderLunchWidget.bind(this)); + return Promise.all([def, this._super.apply(this, arguments)]); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + _onAddProduct: function (ev) { + var self = this; + ev.stopPropagation(); + + this._rpc({ + model: 'lunch.order', + method: 'update_quantity', + args: [[ev.data.lineId], 1], + }).then(function () { + self.reload(); + }); + }, + _onLocationChanged: function (ev) { + var self = this; + + ev.stopPropagation(); + + this._rpc({ + route: '/lunch/user_location_set', + params: { + user_id: this.userId, + location_id: ev.data.locationId, + context: this.context, + }, + }).then(function () { + self.model._updateLocation(ev.data.locationId).then(function () { + self.reload(); + }); + }); + }, + _onOpenWizard: function (ev) { + var self = this; + ev.stopPropagation(); + + var ctx = this.userId ? {default_user_id: this.userId} : {}; + + var options = { + on_close: function () { + self.reload(); + }, + }; + + // YTI TODO Maybe don't always pass the default_product_id + var action = { + res_model: 'lunch.order', + name: _t('Configure Your Order'), + type: 'ir.actions.act_window', + views: [[false, 'form']], + target: 'new', + context: _.extend(ctx, {default_product_id: ev.data.productId}), + }; + + if (ev.data.lineId) { + action = _.extend(action, { + res_id: ev.data.lineId, + context: _.extend(action.context, { + active_id: ev.data.lineId, + }), + }); + } + + this.do_action(action, options); + }, + _onOrderNow: function (ev) { + var self = this; + ev.stopPropagation(); + + this._rpc({ + route: '/lunch/pay', + params: { + user_id: this.userId, + context: this.context, + }, + }).then(function (isPaid) { + if (isPaid) { + // TODO: feedback? + self.reload(); + } else { + self._showPaymentDialog(_t("Not enough money in your wallet")); + self.reload(); + } + }); + }, + _onRemoveProduct: function (ev) { + var self = this; + ev.stopPropagation(); + + this._rpc({ + model: 'lunch.order', + method: 'update_quantity', + args: [[ev.data.lineId], -1], + }).then(function () { + self.reload(); + }); + }, + _onUserChanged: function (ev) { + ev.stopPropagation(); + + var self = this; + + this.userId = ev.data.userId; + this.model._updateUser(ev.data.userId).then(function () { + self.reload(); + }); + }, + _onUnlinkOrder: function (ev) { + var self = this; + ev.stopPropagation(); + + this._rpc({ + route: '/lunch/trash', + params: { + user_id: this.userId, + context: this.context, + }, + }).then(function () { + self.reload(); + }); + }, +}; + +return LunchControllerCommon; + +}); diff --git a/addons/lunch/static/src/js/lunch_kanban_controller.js b/addons/lunch/static/src/js/lunch_kanban_controller.js index 6e75d4839b3..dc370a46277 100644 --- a/addons/lunch/static/src/js/lunch_kanban_controller.js +++ b/addons/lunch/static/src/js/lunch_kanban_controller.js @@ -6,248 +6,11 @@ odoo.define('lunch.LunchKanbanController', function (require) { * override of the KanbanController. */ -var session = require('web.session'); -var core = require('web.core'); var KanbanController = require('web.KanbanController'); -var LunchKanbanWidget = require('lunch.LunchKanbanWidget'); -var LunchPaymentDialog = require('lunch.LunchPaymentDialog'); +var LunchControllerCommon = require('lunch.LunchControllerCommon'); -var _t = core._t; - -var LunchKanbanController = KanbanController.extend({ - custom_events: _.extend({}, KanbanController.prototype.custom_events, { - add_product: '_onAddProduct', - change_location: '_onLocationChanged', - change_user: '_onUserChanged', - open_wizard: '_onOpenWizard', - order_now: '_onOrderNow', - remove_product: '_onRemoveProduct', - unlink_order: '_onUnlinkOrder', - }), - - /** - * @override - */ - init: function () { - this.userId = null; - this.editMode = false; - this.updated = false; - this.widgetData = null; - this.context = session.user_context; - return this._super.apply(this, arguments); - }, - /** - * @override - */ - start: function () { - // create a div inside o_content that will be used to wrap the lunch - // banner and kanban renderer (this is required to get the desired - // layout with the searchPanel to the left) - var self = this; - this.$('.o_content').append($('<div>').addClass('o_lunch_kanban')); - return this._super.apply(this, arguments).then(function () { - self.$('.o_lunch_kanban').append(self.$('.o_kanban_view')); - }); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - _fetchPaymentInfo: function () { - return this._rpc({ - route: '/lunch/payment_message', - params: { - context: this.context, - }, - }); - }, - _fetchWidgetData: function () { - var self = this; - - return this._rpc({ - route: '/lunch/infos', - params: { - user_id: this.userId, - context: this.context, - }, - }).then(function (data) { - self.widgetData = data; - return self.model._updateLocation(data.user_location[0]); - }); - }, - /** - * Override to add the location domain (coming from the lunchKanbanWidget) - * to the searchDomain (coming from the controlPanel). - * - * @override - */ - _getViewDomain: async function () { - return this.model.getLocationDomain(); - }, - /** - * Renders and appends the lunch banner widget. - * - * @private - */ - _renderLunchKanbanWidget: function () { - var self = this; - var oldWidget = this.widget; - 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); - if (oldWidget) { - oldWidget.destroy(); - } - }); - }, - _showPaymentDialog: function (title) { - var self = this; - - title = title || ''; - - this._fetchPaymentInfo().then(function (data) { - var paymentDialog = new LunchPaymentDialog(self, _.extend(data, {title: title})); - paymentDialog.open(); - }); - }, - /** - * Override to fetch and display the lunch data. Because of the presence of - * the searchPanel, also wrap the lunch widget and the kanban renderer into - * a div, to get the desired layout. - * - * @override - * @private - */ - _update: function () { - var def = this._fetchWidgetData().then(this._renderLunchKanbanWidget.bind(this)); - return Promise.all([def, this._super.apply(this, arguments)]); - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - _onAddProduct: function (ev) { - var self = this; - ev.stopPropagation(); - - this._rpc({ - model: 'lunch.order', - method: 'update_quantity', - args: [[ev.data.lineId], 1], - }).then(function () { - self.reload(); - }); - }, - _onLocationChanged: function (ev) { - var self = this; - - ev.stopPropagation(); - - this._rpc({ - route: '/lunch/user_location_set', - params: { - user_id: this.userId, - location_id: ev.data.locationId, - context: this.context, - }, - }).then(function () { - self.model._updateLocation(ev.data.locationId).then(function () { - self.reload(); - }); - }); - }, - _onOpenWizard: function (ev) { - var self = this; - ev.stopPropagation(); - - var ctx = this.userId ? {default_user_id: this.userId} : {}; - - var options = { - on_close: function () { - self.reload(); - }, - }; - - // YTI TODO Maybe don't always pass the default_product_id - var action = { - res_model: 'lunch.order', - name: _t('Configure Your Order'), - type: 'ir.actions.act_window', - views: [[false, 'form']], - target: 'new', - context: _.extend(ctx, {default_product_id: ev.data.productId}), - }; - - if (ev.data.lineId) { - action = _.extend(action, { - res_id: ev.data.lineId, - context: _.extend(action.context, { - active_id: ev.data.lineId, - }), - }); - } - - this.do_action(action, options); - }, - _onOrderNow: function (ev) { - var self = this; - ev.stopPropagation(); - - this._rpc({ - route: '/lunch/pay', - params: { - user_id: this.userId, - context: this.context, - }, - }).then(function (isPaid) { - if (isPaid) { - // TODO: feedback? - self.reload(); - } else { - self._showPaymentDialog(_t("Not enough money in your wallet")); - self.reload(); - } - }); - }, - _onRemoveProduct: function (ev) { - var self = this; - ev.stopPropagation(); - - this._rpc({ - model: 'lunch.order', - method: 'update_quantity', - args: [[ev.data.lineId], -1], - }).then(function () { - self.reload(); - }); - }, - _onUserChanged: function (ev) { - ev.stopPropagation(); - - var self = this; - - this.userId = ev.data.userId; - this.model._updateUser(ev.data.userId).then(function () { - self.reload(); - }); - }, - _onUnlinkOrder: function (ev) { - var self = this; - ev.stopPropagation(); - - this._rpc({ - route: '/lunch/trash', - params: { - user_id: this.userId, - context: this.context, - }, - }).then(function () { - self.reload(); - }); - }, +var LunchKanbanController = KanbanController.extend(LunchControllerCommon , { + custom_events: _.extend({}, KanbanController.prototype.custom_events, LunchControllerCommon.custom_events), }); return LunchKanbanController; diff --git a/addons/lunch/static/src/js/lunch_kanban_renderer.js b/addons/lunch/static/src/js/lunch_kanban_renderer.js index bffe639a655..bea87992928 100644 --- a/addons/lunch/static/src/js/lunch_kanban_renderer.js +++ b/addons/lunch/static/src/js/lunch_kanban_renderer.js @@ -19,7 +19,7 @@ var LunchKanbanRenderer = KanbanRenderer.extend({ * @override */ start: function () { - this.$el.addClass('o_lunch_kanban_view position-relative align-content-start flex-grow-1 flex-shrink-1'); + this.$el.addClass('o_lunch_view o_lunch_kanban_view position-relative align-content-start flex-grow-1 flex-shrink-1'); return this._super.apply(this, arguments); }, }); diff --git a/addons/lunch/static/src/js/lunch_kanban_view.js b/addons/lunch/static/src/js/lunch_kanban_view.js index 0b54497fc55..75fda433b2c 100644 --- a/addons/lunch/static/src/js/lunch_kanban_view.js +++ b/addons/lunch/static/src/js/lunch_kanban_view.js @@ -2,7 +2,7 @@ odoo.define('lunch.LunchKanbanView', function (require) { "use strict"; var LunchKanbanController = require('lunch.LunchKanbanController'); -var LunchKanbanModel = require('lunch.LunchKanbanModel'); +var LunchModel = require('lunch.LunchModel'); var LunchKanbanRenderer = require('lunch.LunchKanbanRenderer'); var core = require('web.core'); @@ -14,7 +14,7 @@ var _lt = core._lt; var LunchKanbanView = KanbanView.extend({ config: _.extend({}, KanbanView.prototype.config, { Controller: LunchKanbanController, - Model: LunchKanbanModel, + Model: LunchModel, Renderer: LunchKanbanRenderer, }), display_name: _lt('Lunch Kanban'), diff --git a/addons/lunch/static/src/js/lunch_list_controller.js b/addons/lunch/static/src/js/lunch_list_controller.js new file mode 100644 index 00000000000..bdfbab6b107 --- /dev/null +++ b/addons/lunch/static/src/js/lunch_list_controller.js @@ -0,0 +1,18 @@ +odoo.define('lunch.LunchListController', function (require) { +"use strict"; + +/** + * This file defines the Controller for the Lunch List view, which is an + * override of the ListController. + */ + +var ListController = require('web.ListController'); +var LunchControllerCommon = require('lunch.LunchControllerCommon'); + +var LunchListController = ListController.extend(LunchControllerCommon, { + custom_events: _.extend({}, ListController.prototype.custom_events, LunchControllerCommon.custom_events), +}); + +return LunchListController; + +}); diff --git a/addons/lunch/static/src/js/lunch_list_renderer.js b/addons/lunch/static/src/js/lunch_list_renderer.js new file mode 100644 index 00000000000..0ab0b5c9c13 --- /dev/null +++ b/addons/lunch/static/src/js/lunch_list_renderer.js @@ -0,0 +1,56 @@ +odoo.define('lunch.LunchListRenderer', function (require) { +"use strict"; + +/** + * This file defines the Renderer for the Lunch List view, which is an + * override of the ListRenderer. + */ + +var ListRenderer = require('web.ListRenderer'); + +var LunchListRenderer = ListRenderer.extend({ + events: _.extend({}, ListRenderer.prototype.events, { + 'click .o_data_row': '_onClickListRow', + }), + + /** + * @override + */ + start: function () { + this.$el.addClass('o_lunch_view o_lunch_list_view'); + return this._super.apply(this, arguments); + }, + /** + * Override to add id of product_id in dataset. + * + * @override + */ + _renderRow: function (record) { + var tr = this._super.apply(this, arguments); + tr.attr('data-product-id', record.data.id); + return tr; + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Open the add product wizard + * + * @private + * @param {MouseEvent} ev Click event + */ + _onClickListRow: function (ev) { + ev.preventDefault(); + var productId = ev.currentTarget.dataset && ev.currentTarget.dataset.productId ? parseInt(ev.currentTarget.dataset.productId) : null; + + if (productId) { + this.trigger_up('open_wizard', {productId: productId}); + } + }, +}); + +return LunchListRenderer; + +}); diff --git a/addons/lunch/static/src/js/lunch_list_view.js b/addons/lunch/static/src/js/lunch_list_view.js new file mode 100644 index 00000000000..b49d4386ffb --- /dev/null +++ b/addons/lunch/static/src/js/lunch_list_view.js @@ -0,0 +1,39 @@ +odoo.define('lunch.LunchListView', function (require) { +"use strict"; + +var LunchListController = require('lunch.LunchListController'); +var LunchModel = require('lunch.LunchModel'); +var LunchListRenderer = require('lunch.LunchListRenderer'); + +var core = require('web.core'); +var ListView = require('web.ListView'); +var view_registry = require('web.view_registry'); + +var _lt = core._lt; + +var LunchListView = ListView.extend({ + config: _.extend({}, ListView.prototype.config, { + Controller: LunchListController, + Model: LunchModel, + Renderer: LunchListRenderer, + }), + display_name: _lt('Lunch List'), + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _getViewDomain: function (parent) { + const model = this.getModel(parent); + return model.getLocationDomain(); + }, +}); + +view_registry.add('lunch_list', LunchListView); + +return LunchListView; + +}); diff --git a/addons/lunch/static/src/js/lunch_kanban_mobile.js b/addons/lunch/static/src/js/lunch_mobile.js index eddd22ac351..f6ad1e92081 100644 --- a/addons/lunch/static/src/js/lunch_kanban_mobile.js +++ b/addons/lunch/static/src/js/lunch_mobile.js @@ -1,16 +1,17 @@ -odoo.define('lunch.LunchKanbanMobile', function (require) { +odoo.define('lunch.LunchMobile', function (require) { "use strict"; var config = require('web.config'); -var LunchKanbanWidget = require('lunch.LunchKanbanWidget'); +var LunchWidget = require('lunch.LunchWidget'); var LunchKanbanController = require('lunch.LunchKanbanController'); +var LunchListController = require('lunch.LunchListController'); if (!config.device.isMobile) { return; } -LunchKanbanWidget.include({ - template: "LunchKanbanWidgetMobile", +LunchWidget.include({ + template: "LunchWidgetMobile", /** * Override to set the toggle state allowing initially open it. @@ -23,7 +24,7 @@ LunchKanbanWidget.include({ }, }); -LunchKanbanController.include({ +var mobileFunctions = { /** * @override */ @@ -42,7 +43,7 @@ LunchKanbanController.include({ * @override * @private */ - _renderLunchKanbanWidget: function () { + _renderLunchWidget: function () { this.widgetData.keepOpen = this.openWidget; this.openWidget = false; return this._super.apply(this, arguments); @@ -69,6 +70,9 @@ LunchKanbanController.include({ this.openWidget = true; this._super.apply(this, arguments); }, -}); +}; + +LunchKanbanController.include(mobileFunctions); +LunchListController.include(mobileFunctions); }); diff --git a/addons/lunch/static/src/js/lunch_kanban_model.js b/addons/lunch/static/src/js/lunch_model.js index 07acbcd8b69..cd99b6ff834 100644 --- a/addons/lunch/static/src/js/lunch_kanban_model.js +++ b/addons/lunch/static/src/js/lunch_model.js @@ -1,4 +1,4 @@ -odoo.define('lunch.LunchKanbanModel', function (require) { +odoo.define('lunch.LunchModel', function (require) { "use strict"; /** @@ -7,9 +7,9 @@ odoo.define('lunch.LunchKanbanModel', function (require) { */ var session = require('web.session'); -var KanbanModel = require('web.KanbanModel'); +var BasicModel = require('web.BasicModel'); -var LunchKanbanModel = KanbanModel.extend({ +var LunchModel = BasicModel.extend({ init: function () { this.locationId = false; this.userId = false; @@ -125,6 +125,6 @@ var LunchKanbanModel = KanbanModel.extend({ } }); -return LunchKanbanModel; +return LunchModel; }); diff --git a/addons/lunch/static/src/js/lunch_kanban_widget.js b/addons/lunch/static/src/js/lunch_widget.js index 2080590acd1..ca0c497ceff 100644 --- a/addons/lunch/static/src/js/lunch_kanban_widget.js +++ b/addons/lunch/static/src/js/lunch_widget.js @@ -1,4 +1,4 @@ -odoo.define('lunch.LunchKanbanWidget', function (require) { +odoo.define('lunch.LunchWidget', function (require) { "use strict"; var core = require('web.core'); @@ -17,8 +17,8 @@ var LunchMany2One = FieldMany2One.extend({ } }); -var LunchKanbanWidget = Widget.extend({ - template: 'LunchKanbanWidget', +var LunchWidget = Widget.extend({ + template: 'LunchWidget', custom_events: { field_changed: '_onFieldChanged', }, @@ -125,7 +125,6 @@ var LunchKanbanWidget = Widget.extend({ _onAddProduct: function (ev) { ev.preventDefault(); ev.stopPropagation(); - this.trigger_up('add_product', {lineId: $(ev.currentTarget).data('id')}); }, _onOrderNow: function (ev) { @@ -164,6 +163,6 @@ var LunchKanbanWidget = Widget.extend({ }, }); -return LunchKanbanWidget; +return LunchWidget; }); diff --git a/addons/lunch/static/src/scss/lunch_kanban.scss b/addons/lunch/static/src/scss/lunch_kanban.scss index 7e660ae4b43..b4ffa97c8fe 100644 --- a/addons/lunch/static/src/scss/lunch_kanban.scss +++ b/addons/lunch/static/src/scss/lunch_kanban.scss @@ -1,86 +1,8 @@ -.o_lunch_kanban { - display: flex; - flex-direction: column; // display lunch widget above kanban renderer - flex: 1 1 100%; // displayed to the right of the searchPanel - min-width: 0; // prevent grouped kanban from horizontally overflowing - height: 100%; - .o_lunch_kanban_banner { - flex: 0 0 auto; - border-bottom: 1px solid #CED4DA; - background-color: white; - } +.o_lunch_content { .o_kanban_view { flex: 1 1 100%; &.o_kanban_grouped { min-height: auto; // override min-height: 100% } } - - .o_lunch_purple { - color: $o-brand-odoo; - } - - .o_flex_basis_0 { - flex-basis: 0; - } - - .o_lunch_widget { - min-height: 90px; - max-height: 33vh; - overflow-y: auto; - - .o_lunch_widget_info.card { - &, .card-title, .card-body { - color: $o-main-text-color; - background-color: inherit !important; - } - - .card-title { - font-weight: bold; - margin-bottom: 0; - } - - .card-body { - padding: 0.5rem 1rem; - } - - .btn-link { - padding: 0; - &.o_lunch_open_wizard { - color: $o-main-text-color; - font-weight: normal; - } - } - } - } -} - -.o_lunch_image { - img { - max-width: 128px; - max-height: 128px !important; - } -} - -@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% - } - } -} - -.o_lunch_wizard { - .col-10 { - .o_form_label { - font-weight: normal !important; - } - } } diff --git a/addons/lunch/static/src/scss/lunch_list.scss b/addons/lunch/static/src/scss/lunch_list.scss index 2babc5e388e..b0afa58aeaf 100644 --- a/addons/lunch/static/src/scss/lunch_list.scss +++ b/addons/lunch/static/src/scss/lunch_list.scss @@ -1,5 +1,11 @@ -.o_lunch_list { +.o_lunch_content { .o_list_button { width: 1px; } + + .o_lunch_list_view { + td:last-child { + padding-right: 16px; + } + } }
\ No newline at end of file diff --git a/addons/lunch/static/src/scss/lunch_view.scss b/addons/lunch/static/src/scss/lunch_view.scss new file mode 100644 index 00000000000..6b7056f96f7 --- /dev/null +++ b/addons/lunch/static/src/scss/lunch_view.scss @@ -0,0 +1,81 @@ +.o_lunch_content { + display: flex; + flex-direction: column; // display lunch widget above kanban renderer + flex: 1 1 100%; // displayed to the right of the searchPanel + min-width: 0; // prevent grouped kanban from horizontally overflowing + max-width: 100%; + height: 100%; + .o_lunch_banner { + flex: 0 0 auto; + border-bottom: 1px solid #CED4DA; + background-color: white; + } + + .o_lunch_purple { + color: $o-brand-odoo; + } + + .o_flex_basis_0 { + flex-basis: 0; + } + + .o_lunch_widget { + min-height: 90px; + max-height: 33vh; + overflow-y: auto; + + .o_lunch_widget_info.card { + &, .card-title, .card-body { + color: $o-main-text-color; + background-color: inherit !important; + } + + .card-title { + font-weight: bold; + margin-bottom: 0; + } + + .card-body { + padding: 0.5rem 1rem; + } + + .btn-link { + padding: 0; + &.o_lunch_open_wizard { + color: $o-main-text-color; + font-weight: normal; + } + } + } + } +} + +.o_lunch_image { + img { + max-width: 128px; + max-height: 128px !important; + } +} + +@include media-breakpoint-down(sm) { + .o_lunch_content { + 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% + } + } +} + +.o_lunch_wizard { + .col-10 { + .o_form_label { + font-weight: normal !important; + } + } +} diff --git a/addons/lunch/static/src/xml/lunch_kanban.xml b/addons/lunch/static/src/xml/lunch_templates.xml index aab22eaf4ae..6cc7872189f 100644 --- a/addons/lunch/static/src/xml/lunch_kanban.xml +++ b/addons/lunch/static/src/xml/lunch_templates.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <templates> - <span t-name="LunchKanbanWidget"> + <span t-name="LunchWidget"> <t t-foreach="widget.alerts" t-as="alert"> <div class="alert alert-warning mb-0" role="alert"> <t t-raw="alert.message"/> <!-- alert.message is coming from a fields.Html so it should be safe --> </div> </t> - <div class="o_lunch_kanban_banner container-fluid"> + <div class="o_lunch_banner container-fluid"> <div class="o_lunch_widget row py-3 py-md-0"> <div class="o_lunch_widget_info col-12 col-md-4 card border-0"> <div class="card-body row no-gutters align-items-center"> @@ -116,7 +116,7 @@ <span t-esc="widget.message"/> </div> - <t t-name="LunchKanbanWidgetMobile"> + <t t-name="LunchWidgetMobile"> <details class="fixed-bottom" t-attf-open="#{widget.keepOpen}"> <summary class="o_lunch_toggle_cart btn btn-primary w-100"> <i class="fa fa-fw fa-shopping-cart"/> @@ -126,7 +126,7 @@ <t t-set="currency" t-value="widget.currency"/> </t>) </summary> - <t t-call="LunchKanbanWidget"/> + <t t-call="LunchWidget"/> </details> </t> </templates> diff --git a/addons/lunch/static/tests/lunch_kanban_mobile_tests.js b/addons/lunch/static/tests/lunch_kanban_mobile_tests.js index f17bef77f8c..1f2e61ff423 100644 --- a/addons/lunch/static/tests/lunch_kanban_mobile_tests.js +++ b/addons/lunch/static/tests/lunch_kanban_mobile_tests.js @@ -4,7 +4,7 @@ odoo.define('lunch.lunchKanbanMobileTests', function (require) { const LunchKanbanView = require('lunch.LunchKanbanView'); const testUtils = require('web.test_utils'); -const {createLunchKanbanView, mockLunchRPC} = require('lunch.test_utils'); +const {createLunchView, mockLunchRPC} = require('lunch.test_utils'); QUnit.module('Views'); @@ -61,7 +61,7 @@ QUnit.module('LunchKanbanView Mobile', { QUnit.test('basic rendering', async function (assert) { assert.expect(7); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -84,27 +84,27 @@ QUnit.module('LunchKanbanView Mobile', { "should have 1 records in the renderer"); // check view layout - assert.containsOnce(kanban, '.o_content > .o_lunch_kanban', + assert.containsOnce(kanban, '.o_content > .o_lunch_content', "should have a 'kanban lunch wrapper' column"); - assert.containsOnce(kanban, '.o_lunch_kanban > .o_kanban_view', + assert.containsOnce(kanban, '.o_lunch_content > .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', + assert.containsOnce($('.o_lunch_content'), '> details', "should have a 'lunch kanban' details/summary discolure panel"); - assert.hasClass($('.o_lunch_kanban > details'), 'fixed-bottom', + assert.hasClass($('.o_lunch_content > details'), 'fixed-bottom', "should have classname 'fixed-bottom'"); - assert.isNotVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + assert.isNotVisible($('.o_lunch_content > details .o_lunch_banner'), "shouldn't have a visible 'lunch kanban' banner"); kanban.destroy(); }); - QUnit.module('LunchKanbanWidget', function () { + QUnit.module('LunchWidget', function () { QUnit.test('toggle', async function (assert) { assert.expect(6); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -125,8 +125,8 @@ QUnit.module('LunchKanbanView Mobile', { }), }); - const $details = $('.o_lunch_kanban > details'); - assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + const $details = $('.o_lunch_content > details'); + assert.isNotVisible($details.find('.o_lunch_banner'), "shouldn't have a visible 'lunch kanban' banner"); assert.isVisible($details.find('> summary'), "should hava a visible cart toggle button"); @@ -136,11 +136,11 @@ QUnit.module('LunchKanbanView Mobile', { "should have '3.00' in the button text"); await testUtils.dom.click($details.find('> summary')); - assert.isVisible($details.find('.o_lunch_kanban_banner'), + assert.isVisible($details.find('.o_lunch_banner'), "should have a visible 'lunch kanban' banner"); await testUtils.dom.click($details.find('> summary')); - assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + assert.isNotVisible($details.find('.o_lunch_banner'), "shouldn't have a visible 'lunch kanban' banner"); kanban.destroy(); @@ -149,7 +149,7 @@ QUnit.module('LunchKanbanView Mobile', { QUnit.test('keep open when adding quantities', async function (assert) { assert.expect(6); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -177,14 +177,14 @@ QUnit.module('LunchKanbanView Mobile', { }), }); - const $details = $('.o_lunch_kanban > details'); - assert.isNotVisible($details.find('.o_lunch_kanban_banner'), + const $details = $('.o_lunch_content > details'); + assert.isNotVisible($details.find('.o_lunch_banner'), "shouldn't have a visible 'lunch kanban' banner"); assert.isVisible($details.find('> summary'), "should hava a visible cart toggle button"); await testUtils.dom.click($details.find('> summary')); - assert.isVisible($details.find('.o_lunch_kanban_banner'), + assert.isVisible($details.find('.o_lunch_banner'), "should have a visible 'lunch kanban' banner"); const $widgetSecondColumn = kanban.$('.o_lunch_widget .o_lunch_widget_info:eq(1)'); @@ -195,13 +195,13 @@ QUnit.module('LunchKanbanView Mobile', { let $firstLine = $widgetSecondColumn.find('.o_lunch_widget_lines > li:first'); await testUtils.dom.click($firstLine.find('button.o_add_product')); - assert.isVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + assert.isVisible($('.o_lunch_content > details .o_lunch_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'); await testUtils.dom.click($firstLine.find('button.o_remove_product')); - assert.isVisible($('.o_lunch_kanban > details .o_lunch_kanban_banner'), + assert.isVisible($('.o_lunch_content > details .o_lunch_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 index bb2b0beb3f7..d4deade79bb 100644 --- a/addons/lunch/static/tests/lunch_kanban_tests.js +++ b/addons/lunch/static/tests/lunch_kanban_tests.js @@ -4,7 +4,7 @@ odoo.define('lunch.lunchKanbanTests', function (require) { const LunchKanbanView = require('lunch.LunchKanbanView'); const testUtils = require('web.test_utils'); -const {createLunchKanbanView, mockLunchRPC} = require('lunch.test_utils'); +const {createLunchView, mockLunchRPC} = require('lunch.test_utils'); QUnit.module('Views'); @@ -89,7 +89,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('basic rendering', async function (assert) { assert.expect(7); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -116,14 +116,14 @@ QUnit.module('LunchKanbanView', { "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', + assert.containsOnce(kanban, '.o_content > .o_lunch_content', + "should have a 'lunch wrapper' column"); + assert.containsOnce(kanban, '.o_lunch_content > .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 > span > .o_lunch_kanban_banner', - "should have a 'lunch kanban' banner"); + assert.containsOnce(kanban, '.o_lunch_content > span > .o_lunch_banner', + "should have a 'lunch' banner"); kanban.destroy(); }); @@ -133,7 +133,7 @@ QUnit.module('LunchKanbanView', { const self = this; let infosProm = Promise.resolve(); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -175,12 +175,12 @@ QUnit.module('LunchKanbanView', { kanban.destroy(); }); - QUnit.module('LunchKanbanWidget', function () { + QUnit.module('LunchWidget', function () { QUnit.test('empty cart', async function (assert) { assert.expect(3); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -217,7 +217,7 @@ QUnit.module('LunchKanbanView', { let locationId = this.data['lunch.location'].records[0].id; const regularInfos = _.extend({}, this.regularInfos); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -285,7 +285,7 @@ QUnit.module('LunchKanbanView', { assert.expect(10); const regularInfos = _.extend({}, this.regularInfos); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -333,7 +333,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('non-empty cart', async function (assert) { assert.expect(17); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -415,7 +415,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('ordered cart', async function (assert) { assert.expect(15); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -491,7 +491,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('confirmed cart', async function (assert) { assert.expect(15); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -567,7 +567,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('regular user', async function (assert) { assert.expect(11); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -626,7 +626,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('manager user', async function (assert) { assert.expect(12); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -690,7 +690,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('add a product', async function (assert) { assert.expect(1); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -732,7 +732,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('add product quantity', async function (assert) { assert.expect(3); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: Object.assign({}, this.data, { @@ -784,7 +784,7 @@ QUnit.module('LunchKanbanView', { QUnit.test('remove product quantity', async function (assert) { assert.expect(3); - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: Object.assign({}, this.data, { @@ -837,7 +837,7 @@ QUnit.module('LunchKanbanView', { assert.expect(1); const self = this; - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -883,7 +883,7 @@ QUnit.module('LunchKanbanView', { assert.expect(1); const self = this; - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, @@ -929,7 +929,7 @@ QUnit.module('LunchKanbanView', { assert.expect(5); const self = this; - const kanban = await createLunchKanbanView({ + const kanban = await createLunchView({ View: LunchKanbanView, model: 'product', data: this.data, diff --git a/addons/lunch/static/tests/lunch_list_tests.js b/addons/lunch/static/tests/lunch_list_tests.js new file mode 100644 index 00000000000..cca644a52a9 --- /dev/null +++ b/addons/lunch/static/tests/lunch_list_tests.js @@ -0,0 +1,267 @@ +odoo.define('lunch.lunchListTests', function (require) { +"use strict"; + +const LunchListView = require('lunch.LunchListView'); + +const testUtils = require('web.test_utils'); +const {createLunchView, mockLunchRPC} = require('lunch.test_utils'); + +QUnit.module('Views'); + +QUnit.module('LunchListView', { + 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 Promise.resolve(); + }, + }, + 'lunch.product.category': { + fields: {}, + records: [], + }, + 'lunch.supplier': { + fields: {}, + records: [], + }, + 'ir.model.data': { + fields: {}, + xmlid_to_res_id() { + return Promise.resolve(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"], + }; + }, +}, function () { + QUnit.test('basic rendering', async function (assert) { + assert.expect(6); + + const list = await createLunchView({ + View: LunchListView, + model: 'product', + data: this.data, + arch: ` + <tree> + <field name="name"/> + </tree> + `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + }); + + // check view layout + assert.containsN(list, '.o_content > div', 2, + "should have 2 columns"); + assert.containsOnce(list, '.o_content > div.o_search_panel', + "should have a 'lunch filters' column"); + assert.containsOnce(list, '.o_content > .o_lunch_content', + "should have a 'lunch wrapper' column"); + assert.containsOnce(list, '.o_lunch_content > .o_list_view', + "should have a 'classical list view' column"); + assert.hasClass(list.$('.o_list_view'), 'o_lunch_list_view', + "should have classname 'o_lunch_list_view'"); + assert.containsOnce(list, '.o_lunch_content > span > .o_lunch_banner', + "should have a 'lunch' banner"); + + list.destroy(); + }); + + QUnit.module('LunchWidget', function () { + + QUnit.test('search panel domain location', async function (assert) { + assert.expect(20); + let expectedLocation = 1; + let locationId = this.data['lunch.location'].records[0].id; + const regularInfos = _.extend({}, this.regularInfos); + + const list = await createLunchView({ + View: LunchListView, + model: 'product', + data: this.data, + arch: ` + <tree> + <field name="name"/> + </tree> + `, + mockRPC: function (route, args) { + assert.step(route); + + if (route.startsWith('/lunch')) { + if (route === '/lunch/user_location_set') { + locationId = args.location_id; + return Promise.resolve(true); + } + return mockLunchRPC({ + infos: regularInfos, + userLocation: locationId, + }).apply(this, arguments); + } + if (args.method === 'search_panel_select_multi_range') { + assert.deepEqual(args.kwargs.search_domain, [["is_available_at", "in", [expectedLocation]]], + 'The initial domain of the search panel must contain the user location'); + } + if (route === '/web/dataset/search_read') { + assert.deepEqual(args.domain, [["is_available_at", "in", [expectedLocation]]], + 'The domain for fetching actual data should be correct'); + } + return this._super.apply(this, arguments); + }, + }); + + expectedLocation = 2; + await testUtils.fields.many2one.clickOpenDropdown('locations'); + await testUtils.fields.many2one.clickItem('locations', "Office 2"); + + assert.verifySteps([ + // Initial state + '/lunch/user_location_get', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/search_read', + '/lunch/infos', + '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id', + // Click m2o + '/web/dataset/call_kw/lunch.location/name_search', + // Click new location + '/lunch/user_location_set', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/search_read', + '/lunch/infos', + '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id', + ]); + + list.destroy(); + }); + + QUnit.test('search panel domain location false: fetch products in all locations', async function (assert) { + assert.expect(10); + const regularInfos = _.extend({}, this.regularInfos); + + const list = await createLunchView({ + View: LunchListView, + model: 'product', + data: this.data, + arch: ` + <tree> + <field name="name"/> + </tree> + `, + mockRPC: function (route, args) { + assert.step(route); + + if (route.startsWith('/lunch')) { + return mockLunchRPC({ + infos: regularInfos, + userLocation: false, + }).apply(this, arguments); + } + if (args.method === 'search_panel_select_multi_range') { + assert.deepEqual(args.kwargs.search_domain, [], + 'The domain should not exist since the location is false.'); + } + if (route === '/web/dataset/search_read') { + assert.deepEqual(args.domain, [], + 'The domain for fetching actual data should be correct'); + } + return this._super.apply(this, arguments); + } + }); + assert.verifySteps([ + '/lunch/user_location_get', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/call_kw/product/search_panel_select_multi_range', + '/web/dataset/search_read', + '/lunch/infos', + '/web/dataset/call_kw/ir.model.data/xmlid_to_res_id', + ]) + + list.destroy(); + }); + + QUnit.test('add a product', async function (assert) { + assert.expect(1); + + const list = await createLunchView({ + View: LunchListView, + model: 'product', + data: this.data, + arch: ` + <tree> + <field name="name"/> + </tree> + `, + mockRPC: mockLunchRPC({ + infos: this.regularInfos, + userLocation: this.data['lunch.location'].records[0].id, + }), + intercepts: { + do_action: function (ev) { + assert.deepEqual(ev.data.action, { + name: "Configure Your Order", + res_model: 'lunch.order', + type: 'ir.actions.act_window', + views: [[false, 'form']], + target: 'new', + context: { + default_product_id: 1, + }, + }, + "should open the wizard"); + }, + }, + }); + + await testUtils.dom.click(list.$('.o_data_row:first')); + + list.destroy(); + }); + }); +}); + +}); diff --git a/addons/lunch/static/tests/lunch_test_utils.js b/addons/lunch/static/tests/lunch_test_utils.js index beef94f80a5..a59328a05dd 100644 --- a/addons/lunch/static/tests/lunch_test_utils.js +++ b/addons/lunch/static/tests/lunch_test_utils.js @@ -6,11 +6,11 @@ const RamStorage = require('web.RamStorage'); const {createView} = require('web.test_utils'); /** - * Helper to create a lunch kanban view with searchpanel + * Helper to create a lunch view with searchpanel * * @param {object} params */ -async function createLunchKanbanView(params) { +async function createLunchView(params) { params.archs = params.archs || {}; var searchArch = params.archs[`${params.model},false,search`] || '<search></search>'; var searchPanelArch = ` @@ -52,7 +52,7 @@ function mockLunchRPC({infos, userLocation}) { } return { - createLunchKanbanView, + createLunchView, mockLunchRPC, }; diff --git a/addons/lunch/views/lunch_product_views.xml b/addons/lunch/views/lunch_product_views.xml index 0c5fb5d0319..7764aa19b45 100644 --- a/addons/lunch/views/lunch_product_views.xml +++ b/addons/lunch/views/lunch_product_views.xml @@ -91,6 +91,21 @@ </form> </field> </record> + <record id="lunch_product_report_view_tree" model="ir.ui.view"> + <field name="name">lunch.product.tree</field> + <field name="model">lunch.product.report</field> + <field name="priority">999</field> + <field name="arch" type="xml"> + <tree js_class="lunch_list"> + <field name="name"/> + <field name="category_id"/> + <field name="supplier_id"/> + <field name="description"/> + <field name="product_id" invisible="1"/> + <field name="price" widget="monetary"/> + </tree> + </field> + </record> <record id="view_lunch_product_kanban_order" model="ir.ui.view"> <field name="name">lunch.product.kanban</field> @@ -330,7 +345,7 @@ <record id="lunch_product_action_order" model="ir.actions.act_window"> <field name="name">Order Your Lunch</field> <field name="res_model">lunch.product.report</field> - <field name="view_mode">kanban</field> + <field name="view_mode">kanban,tree</field> <field name="view_id" ref="view_lunch_product_kanban_order"/> <field name="search_view_id" ref="lunch_product_report_view_search"/> <field name="domain">[('supplier_id.available_today', '=', True), '|', ('user_id', '=', False), ('user_id', '=', uid)]</field> diff --git a/addons/lunch/views/lunch_templates.xml b/addons/lunch/views/lunch_templates.xml index 2fbdb1d3df0..2b2ea02973a 100644 --- a/addons/lunch/views/lunch_templates.xml +++ b/addons/lunch/views/lunch_templates.xml @@ -2,17 +2,22 @@ <odoo> <template id="assets_backend" name="lunch assets" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> + <link rel="stylesheet" type="text/scss" href="/lunch/static/src/scss/lunch_view.scss"/> <link rel="stylesheet" type="text/scss" href="/lunch/static/src/scss/lunch_kanban.scss"/> <link rel="stylesheet" type="text/scss" href="/lunch/static/src/scss/lunch_list.scss"/> - <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_widget.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_controller_common.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_model.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_widget.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_mobile.js"></script> <script type="text/javascript" src="/lunch/static/src/js/lunch_payment_dialog.js"></script> <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_view.js"></script> <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_controller.js"></script> <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_renderer.js"></script> <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_record.js"></script> - <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_model.js"></script> - <script type="text/javascript" src="/lunch/static/src/js/lunch_kanban_mobile.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_list_view.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_list_controller.js"></script> + <script type="text/javascript" src="/lunch/static/src/js/lunch_list_renderer.js"></script> </xpath> </template> @@ -20,6 +25,7 @@ <xpath expr="." position="inside"> <script type="text/javascript" src="/lunch/static/tests/lunch_test_utils.js"></script> <script type="text/javascript" src="/lunch/static/tests/lunch_kanban_tests.js"></script> + <script type="text/javascript" src="/lunch/static/tests/lunch_list_tests.js"></script> </xpath> </template> |
