summaryrefslogtreecommitdiff
path: root/addons/lunch/static
diff options
context:
space:
mode:
authorRomainLibert <rli@odoo.com>2018-10-25 16:43:19 +0200
committerYannick Tivisse <yti@odoo.com>2018-12-04 11:56:21 +0100
commitf727b8f0b57aad49f2ea8c54600ab73bbd02570f (patch)
tree7da43e4b2615476446a28b62c7827788f6113e2a /addons/lunch/static
parentad99f09a062cd190c9863d49486e60899daed2a6 (diff)
[IMP] lunch: automatize lunch orders
We would like to automatize lunch as currently all orders are manually ordered and validated, and a cash move has to be manually created each time you want to credit the wallet of some user. In this commit we add a new widget that comes with the kanban view and will allow to take orders in a friendly manner. We also add a lunch.supplier model and an integration with the hr module in order to filter what products you can order depending on your working location, this also allows you to configure an automatic ordering via email. TaskID: 1856876
Diffstat (limited to 'addons/lunch/static')
-rw-r--r--addons/lunch/static/img/4formaggio.pngbin0 -> 8362 bytes
-rw-r--r--addons/lunch/static/img/Coke.pngbin0 -> 7469 bytes
-rw-r--r--addons/lunch/static/img/bacon_burger.pngbin0 -> 8027 bytes
-rw-r--r--addons/lunch/static/img/brie.pngbin0 -> 6794 bytes
-rw-r--r--addons/lunch/static/img/cheeseburger.pngbin0 -> 7020 bytes
-rw-r--r--addons/lunch/static/img/chicken_curry.pngbin0 -> 7147 bytes
-rw-r--r--addons/lunch/static/img/chirashi.pngbin0 -> 7221 bytes
-rw-r--r--addons/lunch/static/img/club.pngbin0 -> 7011 bytes
-rw-r--r--addons/lunch/static/img/coke_zero.pngbin0 -> 7153 bytes
-rw-r--r--addons/lunch/static/img/fanta.pngbin0 -> 5855 bytes
-rw-r--r--addons/lunch/static/img/fuze_black.pngbin0 -> 5623 bytes
-rw-r--r--addons/lunch/static/img/fuze_green.pngbin0 -> 4724 bytes
-rw-r--r--addons/lunch/static/img/gouda.pngbin0 -> 7864 bytes
-rw-r--r--addons/lunch/static/img/italiana.pngbin0 -> 11549 bytes
-rw-r--r--addons/lunch/static/img/lipton.pngbin0 -> 6784 bytes
-rw-r--r--addons/lunch/static/img/maki.pngbin0 -> 8806 bytes
-rw-r--r--addons/lunch/static/img/mozza.pngbin0 -> 6191 bytes
-rw-r--r--addons/lunch/static/img/napoli.pngbin0 -> 9099 bytes
-rw-r--r--addons/lunch/static/img/pasta_bolognese.pngbin0 -> 6727 bytes
-rw-r--r--addons/lunch/static/img/pizza_funghi.pngbin0 -> 9213 bytes
-rw-r--r--addons/lunch/static/img/pizza_margherita.pngbin0 -> 8597 bytes
-rw-r--r--addons/lunch/static/img/pizza_veggie.pngbin0 -> 7354 bytes
-rw-r--r--addons/lunch/static/img/salmon_sushi.pngbin0 -> 6885 bytes
-rw-r--r--addons/lunch/static/img/temaki.pngbin0 -> 9244 bytes
-rw-r--r--addons/lunch/static/img/tuna_sandwich.pngbin0 -> 6425 bytes
-rw-r--r--addons/lunch/static/src/js/lunch.js94
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_controller.js190
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_model.js19
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_record.js22
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_renderer.js29
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_view.js42
-rw-r--r--addons/lunch/static/src/js/lunch_kanban_widget.js87
-rw-r--r--addons/lunch/static/src/js/lunch_payment_dialog.js24
-rw-r--r--addons/lunch/static/src/scss/lunch.scss14
-rw-r--r--addons/lunch/static/src/scss/lunch_kanban.scss48
-rw-r--r--addons/lunch/static/src/xml/lunch_kanban.xml118
-rw-r--r--addons/lunch/static/tests/lunch_tests.js145
-rw-r--r--addons/lunch/static/tests/test_lunch_kanban.js207
38 files changed, 786 insertions, 253 deletions
diff --git a/addons/lunch/static/img/4formaggio.png b/addons/lunch/static/img/4formaggio.png
new file mode 100644
index 00000000000..f19c95ac934
--- /dev/null
+++ b/addons/lunch/static/img/4formaggio.png
Binary files differ
diff --git a/addons/lunch/static/img/Coke.png b/addons/lunch/static/img/Coke.png
new file mode 100644
index 00000000000..e822a2656ac
--- /dev/null
+++ b/addons/lunch/static/img/Coke.png
Binary files differ
diff --git a/addons/lunch/static/img/bacon_burger.png b/addons/lunch/static/img/bacon_burger.png
new file mode 100644
index 00000000000..ad4177d8ac2
--- /dev/null
+++ b/addons/lunch/static/img/bacon_burger.png
Binary files differ
diff --git a/addons/lunch/static/img/brie.png b/addons/lunch/static/img/brie.png
new file mode 100644
index 00000000000..5b76bfbb1ee
--- /dev/null
+++ b/addons/lunch/static/img/brie.png
Binary files differ
diff --git a/addons/lunch/static/img/cheeseburger.png b/addons/lunch/static/img/cheeseburger.png
new file mode 100644
index 00000000000..f9d5a3e5c01
--- /dev/null
+++ b/addons/lunch/static/img/cheeseburger.png
Binary files differ
diff --git a/addons/lunch/static/img/chicken_curry.png b/addons/lunch/static/img/chicken_curry.png
new file mode 100644
index 00000000000..09e494482d6
--- /dev/null
+++ b/addons/lunch/static/img/chicken_curry.png
Binary files differ
diff --git a/addons/lunch/static/img/chirashi.png b/addons/lunch/static/img/chirashi.png
new file mode 100644
index 00000000000..65143711848
--- /dev/null
+++ b/addons/lunch/static/img/chirashi.png
Binary files differ
diff --git a/addons/lunch/static/img/club.png b/addons/lunch/static/img/club.png
new file mode 100644
index 00000000000..5f3e36f3f37
--- /dev/null
+++ b/addons/lunch/static/img/club.png
Binary files differ
diff --git a/addons/lunch/static/img/coke_zero.png b/addons/lunch/static/img/coke_zero.png
new file mode 100644
index 00000000000..72dbba5542b
--- /dev/null
+++ b/addons/lunch/static/img/coke_zero.png
Binary files differ
diff --git a/addons/lunch/static/img/fanta.png b/addons/lunch/static/img/fanta.png
new file mode 100644
index 00000000000..b7a48332e0d
--- /dev/null
+++ b/addons/lunch/static/img/fanta.png
Binary files differ
diff --git a/addons/lunch/static/img/fuze_black.png b/addons/lunch/static/img/fuze_black.png
new file mode 100644
index 00000000000..1daac338d90
--- /dev/null
+++ b/addons/lunch/static/img/fuze_black.png
Binary files differ
diff --git a/addons/lunch/static/img/fuze_green.png b/addons/lunch/static/img/fuze_green.png
new file mode 100644
index 00000000000..9a274ab6796
--- /dev/null
+++ b/addons/lunch/static/img/fuze_green.png
Binary files differ
diff --git a/addons/lunch/static/img/gouda.png b/addons/lunch/static/img/gouda.png
new file mode 100644
index 00000000000..c50d6d8dfbf
--- /dev/null
+++ b/addons/lunch/static/img/gouda.png
Binary files differ
diff --git a/addons/lunch/static/img/italiana.png b/addons/lunch/static/img/italiana.png
new file mode 100644
index 00000000000..2f8c4244436
--- /dev/null
+++ b/addons/lunch/static/img/italiana.png
Binary files differ
diff --git a/addons/lunch/static/img/lipton.png b/addons/lunch/static/img/lipton.png
new file mode 100644
index 00000000000..a1f8ef21f2e
--- /dev/null
+++ b/addons/lunch/static/img/lipton.png
Binary files differ
diff --git a/addons/lunch/static/img/maki.png b/addons/lunch/static/img/maki.png
new file mode 100644
index 00000000000..c92dd8c83a4
--- /dev/null
+++ b/addons/lunch/static/img/maki.png
Binary files differ
diff --git a/addons/lunch/static/img/mozza.png b/addons/lunch/static/img/mozza.png
new file mode 100644
index 00000000000..8820fbb9cd5
--- /dev/null
+++ b/addons/lunch/static/img/mozza.png
Binary files differ
diff --git a/addons/lunch/static/img/napoli.png b/addons/lunch/static/img/napoli.png
new file mode 100644
index 00000000000..c7ecd65db8a
--- /dev/null
+++ b/addons/lunch/static/img/napoli.png
Binary files differ
diff --git a/addons/lunch/static/img/pasta_bolognese.png b/addons/lunch/static/img/pasta_bolognese.png
new file mode 100644
index 00000000000..64f9972e5c2
--- /dev/null
+++ b/addons/lunch/static/img/pasta_bolognese.png
Binary files differ
diff --git a/addons/lunch/static/img/pizza_funghi.png b/addons/lunch/static/img/pizza_funghi.png
new file mode 100644
index 00000000000..00bceba96b6
--- /dev/null
+++ b/addons/lunch/static/img/pizza_funghi.png
Binary files differ
diff --git a/addons/lunch/static/img/pizza_margherita.png b/addons/lunch/static/img/pizza_margherita.png
new file mode 100644
index 00000000000..0e317265524
--- /dev/null
+++ b/addons/lunch/static/img/pizza_margherita.png
Binary files differ
diff --git a/addons/lunch/static/img/pizza_veggie.png b/addons/lunch/static/img/pizza_veggie.png
new file mode 100644
index 00000000000..950afb54a12
--- /dev/null
+++ b/addons/lunch/static/img/pizza_veggie.png
Binary files differ
diff --git a/addons/lunch/static/img/salmon_sushi.png b/addons/lunch/static/img/salmon_sushi.png
new file mode 100644
index 00000000000..1467b54f120
--- /dev/null
+++ b/addons/lunch/static/img/salmon_sushi.png
Binary files differ
diff --git a/addons/lunch/static/img/temaki.png b/addons/lunch/static/img/temaki.png
new file mode 100644
index 00000000000..8f47e7c035a
--- /dev/null
+++ b/addons/lunch/static/img/temaki.png
Binary files differ
diff --git a/addons/lunch/static/img/tuna_sandwich.png b/addons/lunch/static/img/tuna_sandwich.png
new file mode 100644
index 00000000000..b616d6156a5
--- /dev/null
+++ b/addons/lunch/static/img/tuna_sandwich.png
Binary files differ
diff --git a/addons/lunch/static/src/js/lunch.js b/addons/lunch/static/src/js/lunch.js
deleted file mode 100644
index 8c455083b0d..00000000000
--- a/addons/lunch/static/src/js/lunch.js
+++ /dev/null
@@ -1,94 +0,0 @@
-odoo.define('lunch.previous_orders', function (require) {
-"use strict";
-
-var AbstractField = require('web.AbstractField');
-var core = require('web.core');
-var field_registry = require('web.field_registry');
-var field_utils = require('web.field_utils');
-
-var QWeb = core.qweb;
-
-var LunchPreviousOrdersWidget = AbstractField.extend({
- events: {
- 'click .o_add_button': '_onAddOrder',
- },
- supportedFieldTypes: ['one2many'],
- /**
- * @override
- */
- init: function () {
- this._super.apply(this, arguments);
- this.lunchData = JSON.parse(this.value);
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Used by the widget to render the previous order price like a monetary.
- *
- * @private
- * @param {Object} order
- * @returns {string} the monetary formatting of order price
- */
- _formatValue: function (order) {
- var options = _.extend({}, this.nodeOptions, order);
- return field_utils.format.monetary(order.price, this.field, options);
- },
- /**
- * @private
- * @override
- */
- _render: function () {
- if (this.lunchData !== false) {
- // group data by supplier for display
- var categories = _.groupBy(this.lunchData, 'supplier');
- this.$el.html(QWeb.render('LunchPreviousOrdersWidgetList', {
- formatValue: this._formatValue.bind(this),
- categories: categories,
- }));
- } else {
- return this.$el.html(QWeb.render('LunchPreviousOrdersWidgetNoOrder'));
- }
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onAddOrder: function (event) {
- // Get order details from line
- var lineID = parseInt($(event.currentTarget).data('id'));
- if (!lineID) {
- return;
- }
- var values = {
- product_id: {
- id: this.lunchData[lineID].product_id,
- display_name: this.lunchData[lineID].product_name,
- },
- note: this.lunchData[lineID].note,
- price: this.lunchData[lineID].price,
- };
-
- // create a new order line
- this.trigger_up('field_changed', {
- dataPointID: this.dataPointID,
- changes: {
- order_line_ids: {
- operation: 'CREATE',
- data: values,
- },
- },
- });
- },
-});
-
-field_registry.add('previous_order', LunchPreviousOrdersWidget);
-
-});
diff --git a/addons/lunch/static/src/js/lunch_kanban_controller.js b/addons/lunch/static/src/js/lunch_kanban_controller.js
new file mode 100644
index 00000000000..5c9a0228f46
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_controller.js
@@ -0,0 +1,190 @@
+odoo.define('lunch.LunchKanbanController', function (require) {
+"use strict";
+
+/**
+ * This file defines the Controller for the Lunch Kanban view, which is an
+ * override of the KanbanController.
+ */
+
+var core = require('web.core');
+var KanbanController = require('web.KanbanController');
+var LunchKanbanWidget = require('lunch.LunchKanbanWidget');
+var LunchPaymentDialog = require('lunch.LunchPaymentDialog');
+var session = require('web.session');
+
+var qweb = core.qweb;
+var _t = core._t;
+
+var LunchKanbanController = KanbanController.extend({
+ custom_events: _.extend({}, KanbanController.prototype.custom_events, {
+ add_money: '_onAddMoney',
+ add_product: '_onAddProduct',
+ change_user: '_onUserChanged',
+ edit_order: '_onEditOrder',
+ open_wizard: '_onOpenWizard',
+ order_now: '_onOrderNow',
+ remove_product: '_onRemoveProduct',
+ save_order: '_onSaveOrder',
+ unlink_order: '_onUnlinkOrder',
+ }),
+
+ /**
+ * @override
+ */
+ init: function () {
+ this.userId = null;
+ this.editMode = false;
+ return this._super.apply(this, arguments);
+ },
+ start: function () {
+ this.$el.addClass('o_lunch_kanban');
+ return this._super.apply(this, arguments);
+ },
+
+ _fetchPaymentInfo: function (){
+ return this._rpc({
+ route: '/lunch/payment_message',
+ });
+ },
+
+ _onAddMoney: function (ev) {
+ var self = this;
+
+ ev.stopPropagation();
+
+ this._showPaymentDialog(_t('Your wallet is empty!'));
+ },
+ _onAddProduct: function (ev) {
+ var self = this;
+ ev.stopPropagation();
+
+ this._rpc({
+ model: 'lunch.order.line',
+ method: 'update_quantity',
+ args: [[ev.data.lineId], 1],
+ }).then(function () {
+ self.reload();
+ });
+ },
+ _onEditOrder: function (ev) {
+ ev.stopPropagation();
+
+ this.editMode = true;
+ this.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();
+ },
+ };
+
+ this.do_action({
+ res_model: 'lunch.order.line.temp',
+ type: 'ir.actions.act_window',
+ views: [[false, 'form']],
+ target: 'new',
+ context: _.extend(ctx, {default_product_id: ev.data.res_id}),
+ }, options);
+ },
+ _onOrderNow: function (ev) {
+ var self = this;
+ ev.stopPropagation();
+
+ this._rpc({
+ route: '/lunch/pay',
+ params: {
+ user_id: this.userId,
+ },
+ }).then(function (isPaid) {
+ if (isPaid) {
+ // TODO: feedback?
+ self.reload();
+ } else {
+ self._showPaymentDialog();
+ self.reload();
+ }
+ });
+ },
+ _onRemoveProduct: function (ev) {
+ var self = this;
+ ev.stopPropagation();
+
+ this._rpc({
+ model: 'lunch.order.line',
+ method: 'update_quantity',
+ args: [[ev.data.lineId], -1],
+ }).then(function () {
+ self.reload();
+ });
+ },
+ _onSaveOrder: function (ev) {
+ ev.stopPropagation();
+
+ this.editMode = false;
+ this.reload();
+ },
+ _onUserChanged: function (ev) {
+ ev.stopPropagation();
+
+ this.userId = ev.data.userId;
+ this.reload();
+ },
+ _onUnlinkOrder: function (ev) {
+ var self = this;
+ ev.stopPropagation();
+
+ this._rpc({
+ route: '/lunch/trash',
+ params: {
+ user_id: this.userId,
+ },
+ }).then(function () {
+ self.reload();
+ });
+ },
+ _orderPaid: function () {
+ Dialog.alert(this, _t('Your order has been paid have a nice day'), {'title': 'Order Paid'});
+ },
+ _orderNotPaid: function () {
+ this._showPaymentDialog();
+ },
+ _showPaymentDialog: function (title) {
+ var self = this;
+
+ title = title || '';
+
+ this._fetchPaymentInfo().then(function (data) {
+ var paymentDialog = new LunchPaymentDialog(self, _.extend(data, {title: title}));
+ paymentDialog.open();
+ });
+ },
+ _update: function () {
+ var self = this;
+
+ this._rpc({
+ route: '/lunch/infos',
+ params: {
+ user_id: this.userId,
+ },
+ }).then(function (data) {
+ if (self.widget) {
+ self.widget.destroy();
+ }
+ data.wallet = parseFloat(data.wallet).toFixed(2);
+ self.widget = new LunchKanbanWidget(self, _.extend(data, {edit: self.editMode}));
+ self.widget.insertBefore(self.$('.o_kanban_view'));
+ });
+
+ return this._super.apply(this, arguments);
+ },
+});
+
+return LunchKanbanController;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_kanban_model.js b/addons/lunch/static/src/js/lunch_kanban_model.js
new file mode 100644
index 00000000000..c28f5594b7a
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_model.js
@@ -0,0 +1,19 @@
+odoo.define('lunch.LunchKanbanModel', function (require) {
+"use strict";
+
+/**
+ * This file defines the Model for the Lunch Kanban view, which is an
+ * override of the KanbanModel.
+ */
+
+var KanbanModel = require('web.KanbanModel');
+var core = require('web.core');
+
+var _t = core._t;
+
+var LunchKanbanModel = KanbanModel.extend({
+});
+
+return LunchKanbanModel;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_kanban_record.js b/addons/lunch/static/src/js/lunch_kanban_record.js
new file mode 100644
index 00000000000..45a928b892d
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_record.js
@@ -0,0 +1,22 @@
+odoo.define('lunch.LunchKanbanRecord', function (require) {
+"use strict";
+
+/**
+ * This file defines the KanbanRecord for the Lunch Kanban view.
+ */
+
+var KanbanRecord = require('web.KanbanRecord');
+
+var LunchKanbanRecord = KanbanRecord.extend({
+ _onGlobalClick: function (ev) {
+ ev.preventDefault();
+ // ignore clicks on oe_kanban_action elements
+ if (!$(ev.target).hasClass('oe_kanban_action')) {
+ this.trigger_up('open_wizard', {res_id: this.id});
+ }
+ },
+});
+
+return LunchKanbanRecord;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_kanban_renderer.js b/addons/lunch/static/src/js/lunch_kanban_renderer.js
new file mode 100644
index 00000000000..bffe639a655
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_renderer.js
@@ -0,0 +1,29 @@
+odoo.define('lunch.LunchKanbanRenderer', function (require) {
+"use strict";
+
+/**
+ * This file defines the Renderer for the Lunch Kanban view, which is an
+ * override of the KanbanRenderer.
+ */
+
+var LunchKanbanRecord = require('lunch.LunchKanbanRecord');
+
+var KanbanRenderer = require('web.KanbanRenderer');
+
+var LunchKanbanRenderer = KanbanRenderer.extend({
+ config: _.extend({}, KanbanRenderer.prototype.config, {
+ KanbanRecord: LunchKanbanRecord,
+ }),
+
+ /**
+ * @override
+ */
+ start: function () {
+ this.$el.addClass('o_lunch_kanban_view position-relative align-content-start flex-grow-1 flex-shrink-1');
+ return this._super.apply(this, arguments);
+ },
+});
+
+return LunchKanbanRenderer;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_kanban_view.js b/addons/lunch/static/src/js/lunch_kanban_view.js
new file mode 100644
index 00000000000..296ebac08cd
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_view.js
@@ -0,0 +1,42 @@
+odoo.define('lunch.LunchKanbanView', function (require) {
+"use strict";
+
+var LunchKanbanController = require('lunch.LunchKanbanController');
+var LunchKanbanModel = require('lunch.LunchKanbanModel');
+var LunchKanbanRenderer = require('lunch.LunchKanbanRenderer');
+
+var config = require('web.config');
+var core = require('web.core');
+var KanbanView = require('web.KanbanView');
+var view_registry = require('web.view_registry');
+
+var _lt = core._lt;
+
+if (config.device.isMobile) {
+ // use the classical KanbanView in mobile
+ view_registry.add('lunch_kanban', KanbanView);
+ return;
+}
+
+var LunchKanbanView = KanbanView.extend({
+ config: _.extend({}, KanbanView.prototype.config, {
+ Controller: LunchKanbanController,
+ Model: LunchKanbanModel,
+ Renderer: LunchKanbanRenderer,
+ }),
+ display_name: _lt('Lunch Kanban'),
+ groupable: false,
+
+ /**
+ * @override
+ */
+ init: function () {
+ return this._super.apply(this, arguments);
+ },
+});
+
+view_registry.add('lunch_kanban', LunchKanbanView);
+
+return LunchKanbanView;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_kanban_widget.js b/addons/lunch/static/src/js/lunch_kanban_widget.js
new file mode 100644
index 00000000000..cfc81ab8c47
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_kanban_widget.js
@@ -0,0 +1,87 @@
+odoo.define('lunch.LunchKanbanWidget', function (require) {
+"use strict";
+
+var core = require('web.core');
+var session = require('web.session');
+var Widget = require('web.Widget');
+
+var qweb = core.qweb;
+
+var LunchKanbanWidget = Widget.extend({
+ template: 'LunchKanbanWidget',
+ custom_events: {
+ },
+ events: {
+ 'click .o_add_money': '_onAddMoney',
+ 'click .o_add_product': '_onAddProduct',
+ 'click .o_lunch_widget_edit': '_onEditOrder',
+ 'click .o_lunch_widget_order_button': '_onOrderNow',
+ 'click .o_remove_product': '_onRemoveProduct',
+ 'click .o_lunch_widget_save': '_onSaveOrder',
+ 'click .o_lunch_widget_unlink': '_onUnlinkOrder',
+ 'change select': '_onUserChanged',
+ },
+
+ init: function (parent, params) {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.data = params;
+ this.currency = session.get_currency(session.company_currency_id);
+ },
+ renderElement: function () {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.$('select').val(this.data.username);
+ },
+
+ _onAddMoney: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ this.trigger_up('add_money', {});
+ },
+ _onAddProduct: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('add_product', {lineId: $(ev.currentTarget).data('id')});
+ },
+ _onEditOrder: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('edit_order', {});
+ },
+ _onOrderNow: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('order_now', {});
+ },
+ _onRemoveProduct: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('remove_product', {lineId: $(ev.currentTarget).data('id')});
+ },
+ _onSaveOrder: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('save_order', {});
+ },
+ _onUnlinkOrder: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.trigger_up('unlink_order', {});
+ },
+ _onUserChanged: function (ev) {
+ ev.stopPropagation();
+
+ this.trigger_up('change_user', {userId: $(ev.currentTarget).find(':selected').data('user-id')});
+ }
+});
+
+return LunchKanbanWidget;
+
+});
diff --git a/addons/lunch/static/src/js/lunch_payment_dialog.js b/addons/lunch/static/src/js/lunch_payment_dialog.js
new file mode 100644
index 00000000000..00e49299189
--- /dev/null
+++ b/addons/lunch/static/src/js/lunch_payment_dialog.js
@@ -0,0 +1,24 @@
+odoo.define('lunch.LunchPaymentDialog', function (require) {
+"use strict";
+
+var core = require('web.core');
+var Dialog = require('web.Dialog');
+
+var qweb = core.qweb;
+
+var LunchPaymentDialog = Dialog.extend({
+ template: 'lunch.LunchPaymentDialog',
+
+ init: function (parent, options) {
+ var self = this;
+ this._super.apply(this, arguments);
+
+ options = (options || {});
+
+ this.message = options.message || '';
+ },
+});
+
+return LunchPaymentDialog;
+
+});
diff --git a/addons/lunch/static/src/scss/lunch.scss b/addons/lunch/static/src/scss/lunch.scss
deleted file mode 100644
index 9e36f20dbd8..00000000000
--- a/addons/lunch/static/src/scss/lunch.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-
-.o_web_client .o_lunch {
- .o_lunch_last_orders {
- width: 100%;
-
- .o_lunch_vignette {
- padding: 5px 0;
-
- + .o_lunch_vignette {
- border-top: 1px solid $o-brand-lightsecondary;
- }
- }
- }
-}
diff --git a/addons/lunch/static/src/scss/lunch_kanban.scss b/addons/lunch/static/src/scss/lunch_kanban.scss
new file mode 100644
index 00000000000..44bac01fa4b
--- /dev/null
+++ b/addons/lunch/static/src/scss/lunch_kanban.scss
@@ -0,0 +1,48 @@
+.o_lunch_kanban {
+ .o_pink {
+ color: nth($o-colors, 10);
+ }
+
+ .o_lunch_widget {
+ display: flex;
+ overflow: auto;
+ border-bottom: 1px solid #CED4DA;
+ background-color: white;
+ min-height: 90px;
+ max-height: 90px;
+
+ .o_lunch_widget_info {
+ padding: 5px 12px;
+ margin: 4px 8px;
+ width: 300px;
+ flex: 1 1 auto;
+ overflow-y: auto;
+
+ .o_lunch_ordered {
+ color: white;
+ background-color: #F0D970;
+ padding: 1px 3px;
+ border-radius: .25em;
+ }
+
+ .o_lunch_confirmed {
+ color: white;
+ background-color: #00BA4E;
+ padding: 1px 3px;
+ border-radius: .25em;
+ }
+
+ .o_lunch_widget_title {
+ font-weight: bold;
+ font-size: initial;
+ }
+
+ .o_lunch_widget_order_button {
+ display: block;
+ width: 100%;
+ margin-bottom: 4px;
+ margin-top: 12px;
+ }
+ }
+ }
+}
diff --git a/addons/lunch/static/src/xml/lunch_kanban.xml b/addons/lunch/static/src/xml/lunch_kanban.xml
new file mode 100644
index 00000000000..74a57f7cfec
--- /dev/null
+++ b/addons/lunch/static/src/xml/lunch_kanban.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates>
+ <div class="o_lunch_widget" t-name="LunchKanbanWidget">
+ <div class="o_lunch_widget_info d-flex flex-row">
+ <div>
+ <img class="rounded-circle" t-attf-src="{{ widget.data.userimage }}"/>
+ </div>
+ <div class="w-50 ml-2 py-3">
+ <div>
+ <t t-if="widget.data.is_manager">
+ <select class="o_input">
+ <t t-foreach="widget.data.users" t-as="user">
+ <option t-attf-data-user-id="{{ user.id }}" t-attf-value="{{ user.name }}"><t t-esc="user.name"/></option>
+ </t>
+ </select>
+ </t>
+ <t t-else="">
+ <t t-esc="widget.data.username"/>
+ </t>
+ </div>
+ <div class="d-flex flex-row">
+ <span class="flex-grow-1">
+ <i class="fa fa-money"/>
+ <t t-call="currency_field">
+ <t t-set="value" t-value="widget.data.wallet"/>
+ <t t-set="currency" t-value="widget.currency"/>
+ </t>
+ </span>
+ <span>
+ <a class="o_add_money" href="#">Add money</a>
+ </span>
+ </div>
+ </div>
+ </div>
+ <div class="o_lunch_widget_info">
+ <t t-if="widget.data.order">
+ <t t-if="widget.data.state == 'ordered'">
+ <t t-set="state_class" t-value="'o_lunch_ordered'"/>
+ </t>
+ <t t-else="widget.data.state == 'confirmed'">
+ <t t-set="state_class" t-value="'o_lunch_confirmed'"/>
+ </t>
+ <div class="d-flex flex-row">
+ <div class="flex-grow-1">
+ <span class="o_lunch_widget_title">Your order</span>
+ <a href="#"><i t-if="widget.data.state != 'confirmed'" class="fa fa-trash o_lunch_widget_unlink"/></a>
+ <a t-if="widget.data.state == 'ordered' &amp;&amp; !widget.data.edit" href="#" class="o_lunch_widget_edit">Edit</a>
+ <a t-if="widget.data.state == 'ordered' &amp;&amp; widget.data.edit" href="#" class="o_lunch_widget_save">Save</a>
+ </div>
+ <div t-if="widget.data.state != 'new'" t-esc="widget.data.state" t-attf-class="flex-grow-0 {{ state_class }}"/>
+ </div>
+ <div t-foreach="widget.data.lines" t-as="line">
+ <div class="d-flex flex-row">
+ <div class="flex-grow-0">
+ <a class="o_remove_product" t-if="widget.data.state == 'new' || widget.data.edit" t-attf-data-id="{{ line.id }}" href="#"><i class="fa fa-minus-circle"/></a>
+ <span t-esc="line.quantity"/>
+ <a class="o_add_product" t-if="widget.data.state == 'new' || widget.data.edit" t-attf-data-id="{{ line.id }}" href="#"><i class="fa fa-plus-circle"/></a>
+ </div>
+ <div class="flex-grow-1 pl-2">
+ <span t-esc="line.product[0]"/>
+ </div>
+ <div class="flex-grow-0">
+ <t t-call="currency_field">
+ <t t-set="value" t-value="line.product[1]"/>
+ <t t-set="currency" t-value="widget.currency"/>
+ </t>
+ </div>
+ </div>
+ <div t-foreach="line.toppings" t-as="topping" class="d-flex flex-row">
+ <div class="flex-grow-1 pl-5 ml-5">
+ <span>+ <t t-esc="topping[0]"/></span>
+ </div>
+ <div class="flex-grow-0">
+ <t t-call="currency_field">
+ <t t-set="value" t-value="topping[1]"/>
+ <t t-set="currency" t-value="widget.currency"/>
+ </t>
+ </div>
+ </div>
+ </div>
+ </t>
+ </div>
+ <div class="o_lunch_widget_info">
+ <t t-if="widget.data.order &amp;&amp; widget.data.state == 'new'">
+ <div class="d-flex flex-row">
+ <div class="o_lunch_widget_title flex-grow-1">
+ Total
+ </div>
+ <div class="flex-grow-0 pr-1">
+ <t t-call="currency_field">
+ <t t-set="value" t-value="widget.data.total"/>
+ <t t-set="currency" t-value="widget.currency"/>
+ </t>
+ </div>
+ </div>
+ <button class="btn btn-primary o_lunch_widget_order_button" t-attf-data-order-id="{{ widget.data.order }}">ORDER NOW</button>
+ </t>
+ </div>
+ </div>
+
+ <t t-name="currency_field">
+ <t t-if="currency">
+ <t t-if="currency.position == 'after'">
+ <t t-esc="value"/><t t-esc="currency.symbol"/>
+ </t>
+ <t t-else="">
+ <t t-esc="currency.symbol"/><t t-esc="value"/>
+ </t>
+ </t>
+ <t t-else="">
+ <t t-esc="value"/>
+ </t>
+ </t>
+
+ <div t-name="lunch.LunchPaymentDialog">
+ <span t-esc="widget.message"/>
+ </div>
+</templates>
diff --git a/addons/lunch/static/tests/lunch_tests.js b/addons/lunch/static/tests/lunch_tests.js
deleted file mode 100644
index 3ae1e3491cb..00000000000
--- a/addons/lunch/static/tests/lunch_tests.js
+++ /dev/null
@@ -1,145 +0,0 @@
-odoo.define('lunch.tests', function (require) {
-"use strict";
-
-var FormView = require('web.FormView');
-var testUtils = require('web.test_utils');
-
-var createView = testUtils.createView;
-
-QUnit.module('lunch', {
- beforeEach: function () {
- this.data = {
- order: {
- fields: {
- previous_order_widget: {type: 'text'},
- order_line_ids: {type: 'many2many', relation: 'order_line'}
- },
- records: [{
- id: 1,
- name: 'coucou',
- }, {
- id: 2,
- name: 'coucou',
- }, {
- id: 11,
- }],
- },
- order_line: {
- fields: {
- product_id: {type: 'many2one', relation: 'product'},
- note: {type: 'text'},
- price: {type: 'float'},
- },
- },
- supplier: {
- fields: {},
- records: [{
- id: 1,
- display_name: "Coin Gourmant",
- }, {
- id: 2,
- display_name: "Pizza Inn",
- }]
- },
- product: {
- fields: {},
- records: [{
- id: 1,
- name: 'Pizza Margherita',
- }],
- }
- };
- },
-}, function () {
-
- QUnit.test("empty previous_order widget", function (assert) {
- assert.expect(2);
-
- var form = createView({
- View: FormView,
- arch: '<form>' +
- '<sheet>' +
- '<field name="previous_order_widget" widget="previous_order"/>' +
- '<field name="order_line_ids"/>' +
- '</sheet>' +
- '</form>',
- data: this.data,
- model: 'order',
- archs: {
- "order_line,false,list": '<tree string="Orders">' +
- '<field name="product_id"/>' +
- '<field name="note"/>' +
- '<field name="price"/>' +
- '</tree>',
- },
- });
-
- var widgetText = form.$('.o_field_widget[name="previous_order_widget"]').text();
- assert.ok(widgetText.indexOf('This is the first time you order a meal') !== -1,
- "the widget should display its no content text");
- assert.containsNone(form, '.o_lunch_vignette',
- "there should be no vignette");
-
- form.destroy();
- });
-
- QUnit.test("add an order line with previous_order widget", function (assert) {
- assert.expect(4);
-
- var form = createView({
- View: FormView,
- arch: '<form>' +
- '<sheet>' +
- '<field name="previous_order_widget" widget="previous_order"/>' +
- '<field name="order_line_ids"/>' +
- '</sheet>' +
- '</form>',
- data: this.data,
- model: 'order',
- mockRPC: function (route, args) {
- if (args.method === 'default_get') {
- return $.when({
- previous_order_widget: '{' +
- '"8": {' +
- '"note": "coucou",' +
- '"line_id": 8,' +
- '"digits": [69, 2],' +
- '"product_id": 1,' +
- '"currency": "$",' +
- '"supplier": "Pizza Inn",' +
- '"position": "before",' +
- '"price": 6.9,' +
- '"product_name": "Pizza Margherita"' +
- '}' +
- '}'
- });
- }
- return this._super.apply(this, arguments);
- },
- archs: {
- "order_line,false,list": '<tree string="Orders">' +
- '<field name="product_id"/>' +
- '<field name="note"/>' +
- '<field name="price"/>' +
- '</tree>',
- },
- });
-
- assert.containsNone(form, '.o_list_view tr.o_data_row',
- "there should be no row in the one2many list");
-
- assert.containsOnce(form, '.o_lunch_vignette',
- "there should be a vignette");
-
- // add an order
- testUtils.dom.click(form.$('.o_lunch_vignette .o_add_button'));
-
- assert.containsOnce(form, '.o_list_view tr.o_data_row',
- "there should be one new row in the one2many list");
- assert.strictEqual(form.$('.o_list_view tr.o_data_row').text(), "Pizza Margheritacoucou6.90",
- "the line should contain the correct data");
-
- form.destroy();
- });
-});
-});
diff --git a/addons/lunch/static/tests/test_lunch_kanban.js b/addons/lunch/static/tests/test_lunch_kanban.js
new file mode 100644
index 00000000000..b2062609974
--- /dev/null
+++ b/addons/lunch/static/tests/test_lunch_kanban.js
@@ -0,0 +1,207 @@
+odoo.define('lunch.lunchKanbanTests', function (require) {
+"use strict";
+
+var LunchKanbanView = require('lunch.LunchKanbanView');
+var testUtils = require('web.test_utils');
+
+var createView = testUtils.createView;
+
+QUnit.module('Views', {
+ beforeEach: function () {
+ this.data = {
+ product: {
+ fields: {
+ id: {string: 'ID', type: 'integer'},
+ },
+ records: [
+ {id: 1, name: 'Tuna sandwich', price: 3.0},
+ ]
+ },
+ };
+ },
+}, function () {
+ QUnit.module('LunchKanbanView');
+
+ QUnit.test('Simple rendering of LunchKanbanView', function (assert) {
+ assert.expect(8);
+
+ var lunchKanban = createView({
+ View: LunchKanbanView,
+ model: 'product',
+ data: this.data,
+ arch: '<kanban><templates><t t-name="kanban-box">' +
+ '<div>' +
+ '</div>' +
+ '</t></templates></kanban>',
+ mockRPC: function(route, args) {
+ if (route === '/lunch/infos') {
+ return $.when({
+ order: 1,
+ wallet: 20,
+ username: 'Marc Demo',
+ userimage: '',
+ is_manager: false,
+ users: [
+ {id: 1, name: 'Mitchell Admin'},
+ {id: 2, name: 'Marc Demo'},
+ ],
+ total: 7.4,
+ state: 'new',
+ lines: [
+ {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
+ ]
+ });
+ } else if (route.startsWith('data:image/png;base64,')) {
+ return $.when();
+ }
+ return this._super(route, args);
+ },
+ });
+
+ var $section = $(lunchKanban.$('.o_lunch_widget_info')[0]);
+ // username
+ assert.strictEqual($section.find('div:eq(1) div:eq(0)').text().trim(), 'Marc Demo', 'Username should have been Marc Demo');
+ // wallet_balance
+ assert.strictEqual($section.find('div:eq(1) div:eq(1) span:eq(0)').text().trim(), '20.00', 'Wallet balance should have been 20');
+ // your order section
+ $section = $(lunchKanban.$('.o_lunch_widget_info')[1]);
+ // only one line
+ assert.strictEqual($section.find('div:eq(2) div.d-flex').length, 1, 'There should be only one line');
+ // quantity = 1
+ assert.strictEqual($section.find('div:eq(2) div:eq(0) span:eq(0)').text().trim(), '1', 'The line should contain only one product');
+ // buttons to remove and to add product
+ assert.strictEqual($section.find('.o_remove_product').length, 1, 'There should be a remove product button');
+ assert.strictEqual($section.find('.o_add_product').length, 1, 'There should be a add product button');
+
+ $section = $(lunchKanban.$('.o_lunch_widget_info')[2]);
+ // total
+ assert.strictEqual($section.find('div:eq(0) div:eq(1)').text().trim(), '7.4', 'total should be of 7.4');
+ // order now button
+ assert.strictEqual($section.find('button').length, 1, 'order now button should be available');
+
+ lunchKanban.destroy();
+ });
+
+ QUnit.test('User interactions', function (assert) {
+ assert.expect(8);
+
+ var state = 'new';
+
+ var lunchKanban = createView({
+ View: LunchKanbanView,
+ model: 'product',
+ data: this.data,
+ arch: '<kanban><templates><t t-name="kanban-box">' +
+ '<div>' +
+ '</div>' +
+ '</t></templates></kanban>',
+ mockRPC: function(route, args) {
+ if (route === '/lunch/infos') {
+ return $.when({
+ order: 1,
+ wallet: 20,
+ username: 'Marc Demo',
+ userimage: '',
+ is_manager: false,
+ users: [
+ {id: 1, name: 'Mitchell Admin'},
+ {id: 2, name: 'Marc Demo'},
+ ],
+ total: 7.4,
+ state: state,
+ lines: [
+ {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
+ ]
+ });
+ } else if (route === '/lunch/payment_message') {
+ return $.when({message: 'Hello'});
+ } else if (route === '/lunch/pay') {
+ return $.when(true);
+ } else if (args.method === 'update_quantity') {
+ assert.step(args.args);
+ return $.when();
+ } else if (route.startsWith('data:image/png;base64,')) {
+ return $.when();
+ }
+ return this._super(route, args);
+ },
+ });
+
+ lunchKanban.$('.o_add_money').click();
+ var modal = $('.modal-dialog');
+ assert.strictEqual(modal.find('.modal-body').text().trim(), 'Hello', 'Message should have been Hello');
+ modal.find('.btn.btn-primary').click();
+
+ lunchKanban.$('.o_add_product').click();
+ lunchKanban.$('.o_remove_product').click();
+
+ state = 'ordered';
+ lunchKanban.$('.o_lunch_widget_order_button').click();
+ // state is shown
+ assert.strictEqual(lunchKanban.$('.o_lunch_ordered').length, 1, 'state should be shown as ordered');
+ // no more buttons
+ assert.strictEqual(lunchKanban.$('.o_remove_product').length, 0, 'button to remove product should not be shown anymore');
+ assert.strictEqual(lunchKanban.$('.o_add_product').length, 0, 'button to add product should not be shown anymore');
+ state = 'confirmed';
+ lunchKanban.reload();
+ // state is updated
+ assert.strictEqual(lunchKanban.$('.o_lunch_confirmed').length, 1, 'state should be shown as confirmed');
+
+ assert.verifySteps([
+ [[1], 1],
+ [[1], -1],
+ ]);
+
+ lunchKanban.destroy();
+ });
+
+ QUnit.test('Manager interactions', function (assert) {
+ assert.expect(5);
+
+ var lunchKanban = createView({
+ View: LunchKanbanView,
+ model: 'product',
+ data: this.data,
+ arch: '<kanban><templates><t t-name="kanban-box">' +
+ '<div>' +
+ '</div>' +
+ '</t></templates></kanban>',
+ mockRPC: function(route, args) {
+ if (route === '/lunch/infos') {
+ return $.when({
+ order: 1,
+ wallet: 20,
+ username: 'Marc Demo',
+ userimage: '',
+ is_manager: true,
+ users: [
+ {id: 1, name: 'Mitchell Admin'},
+ {id: 2, name: 'Marc Demo'},
+ ],
+ total: 7.4,
+ state: 'new',
+ lines: [
+ {id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
+ ]
+ });
+ } else if (route.startsWith('data:image/png;base64,')) {
+ return $.when();
+ }
+ return this._super(route, args);
+ },
+ });
+
+ var select = lunchKanban.$('select.o_input');
+ var options = select.find('option');
+
+ assert.strictEqual(select.length, 1, 'There should be a selection field');
+ assert.strictEqual(options.length, 2, 'Select should have two options');
+ assert.strictEqual(options.text().trim(), 'Mitchell AdminMarc Demo', 'Options should be the name of the users');
+ assert.strictEqual($(options[0]).data('user-id'), 1, 'user id should be on option');
+ assert.strictEqual($(options[1]).data('user-id'), 2, 'user id should be on option');
+
+ lunchKanban.destroy();
+ });
+});
+
+});