[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>
This commit is contained in:
committed by
Yannick Tivisse
parent
918a5f2cc0
commit
8b6b09fc26
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
});
|
||||
+11
-7
@@ -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);
|
||||
|
||||
});
|
||||
+4
-4
@@ -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;
|
||||
|
||||
});
|
||||
+4
-5
@@ -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;
|
||||
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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>
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user