[IMP] lunch: new lunch widget

The JS widget is simplified, which a cleaner approach.
For the rendering part:
  - the server reads the data
  - the JS widget formats/organizes the data
  - the template renders the data prepared by the widget

Quick summary of the modifications:
1. The associated field is a text field which contains JSON-encoded
data. The data are read server-side, and not client-side anymore.

2. The widget is an AbstractField, no need of ReinitializeWidgetMixin
anymore. No use of the FieldMonetary widget directly, but use a similar
format_value instead (inspired by ShowPaymentLineWidget).

3. Data formatting (call to format_value) is done in the widget, not in
the template anymore. This seems to be the standard way of doing, since
lunch was the only module where format_value was in the template and not
in the widget.

4. The addition of an order line is cleaner since all necessary data
are prepared server-side.
This commit is contained in:
Nicolas Martinelli
2016-11-03 11:41:39 +01:00
committed by Yannick Tivisse
parent 7cf554af54
commit 018144b8ac
5 changed files with 87 additions and 76 deletions
+32 -5
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import datetime
from odoo import api, fields, models, _
@@ -42,12 +43,12 @@ class LunchOrder(models.Model):
'Status', readonly=True, index=True, copy=False,
compute='_compute_order_state', store=True)
alerts = fields.Text(compute='_compute_alerts_get', string="Alerts")
previous_order_ids = fields.Many2many('lunch.order.line', compute='_compute_previous_order_ids',
default=lambda self: self._default_previous_order_ids())
company_id = fields.Many2one('res.company', related='user_id.company_id', store=True)
currency_id = fields.Many2one('res.currency', related='company_id.currency_id', readonly=True, store=True)
cash_move_balance = fields.Monetary(compute='_compute_cash_move_balance', multi='cash_move_balance')
balance_visible = fields.Boolean(compute='_compute_cash_move_balance', multi='cash_move_balance')
previous_order_ids = fields.Many2many('lunch.order.line', compute='_compute_previous_order')
previous_order_widget = fields.Text(compute='_compute_previous_order')
@api.one
@api.depends('order_line_ids')
@@ -74,9 +75,35 @@ class LunchOrder(models.Model):
if self.state == 'new':
self.alerts = alert_msg and '\n'.join(alert_msg) or False
@api.depends('user_id')
def _compute_previous_order_ids(self):
self.previous_order_ids = self._default_previous_order_ids()
@api.multi
@api.depends('user_id', 'state')
def _compute_previous_order(self):
self.ensure_one()
self.previous_order_widget = json.dumps(False)
prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid), ('product_id.active', '!=', False)], limit=20, order='id desc')
# If we use prev_order.ids, we will have duplicates (identical orders).
# Therefore, this following part removes duplicates based on product_id and note.
self.previous_order_ids = {
(order.product_id, order.note): order.id
for order in prev_order
}.values()
if self.previous_order_ids:
lunch_data = {}
for line in self.previous_order_ids:
lunch_data[line.id] = {
'line_id': line.id,
'product_id': line.product_id.id,
'product_name': line.product_id.name,
'supplier': line.supplier.name,
'note': line.note,
'price': line.price,
'currency': line.currency_id.symbol,
'digits': [69, line.currency_id.decimal_places],
'position': line.currency_id.position,
}
self.previous_order_widget = json.dumps(lunch_data)
@api.one
@api.depends('user_id')
+40 -59
View File
@@ -1,75 +1,56 @@
odoo.define('lunch.form_widgets', function (require) {
odoo.define('lunch.previous_orders', function (require) {
"use strict";
var core = require('web.core');
var form_common = require('web.form_common');
var form_widgets = require('web.form_widgets');
var form_relational = require('web.form_relational');
var _t = core._t;
var formats = require('web.formats');
var Model = require('web.Model');
var QWeb = core.qweb;
var LunchPreviousOrdersWidget = form_relational.AbstractManyField.extend(form_common.ReinitializeWidgetMixin, {
className: 'row o_lunch_last_orders',
var LunchPreviousOrdersWidget = form_common.AbstractField.extend({
events: {
'click .o_add_button': 'set_order_line',
},
init: function(field_manager, node) {
this._super.apply(this, arguments);
this.lunch_data = {};
this.fields_to_read = ['product_id', 'supplier', 'note', 'price', 'category_id', 'currency_id'];
this.monetary = new form_widgets.FieldMonetary(field_manager, node); // create instance to use format_value
this.monetary.__edispatcherRegisteredEvents = []; // remove all bind events
},
fetch_value: function(){
var self = this;
return this.dataset.read_ids(this.get('value'), this.fields_to_read)
.then(function(data) {
_.each(data, function(order) {
self.lunch_data[order['id']] = order;
});
return data;
});
},
get_line_value: function(id) {
var data = _.clone(this.lunch_data[id]);
if (typeof this.lunch_data[id]['product_id'][0] != 'undefined'){
data['product_id'] = this.lunch_data[id]['product_id'][0];
}
if (typeof this.lunch_data[id]['supplier'][0] != 'undefined'){
data['supplier'] = this.lunch_data[id]['supplier'][0];
}
if (typeof this.lunch_data[id]['category_id'][0] != 'undefined'){
data['category_id'] = this.lunch_data[id]['category_id'][0];
}
return data;
},
set_order_line: function(event) {
var data = this.get_line_value(parseInt($(event.currentTarget).data('id')));
var order_line_ids = this.field_manager.fields.order_line_ids;
order_line_ids.data_create(data);
order_line_ids.reload_current_view();
'click .o_add_button': 'add_order_line',
},
render_value: function() {
var self = this;
return this.fetch_value().then(function(data) {
if (_.isEmpty(data)) {
return self.$el.html(QWeb.render("lunch_order_widget_no_previous_order"));
this.lunch_data = JSON.parse(this.get('value'));
if (this.lunch_data !== false) {
// Similar to format_value of FieldMonetary
_.each(this.lunch_data, function(k, v) {
k.price_format = formats.format_value(k.price, {type: "float", digits: k.digits});
});
// Group data by supplier for display
var categories = _.groupBy(this.lunch_data, function(p) {
return p['supplier'];
});
this.$el.html(QWeb.render('LunchPreviousOrdersWidgetList', {'categories': categories}));
} else {
return this.$el.html(QWeb.render('LunchPreviousOrdersWidgetNoOrder'));
}
},
add_order_line: function(event) {
// Get order details from line
var line_id = parseInt($(event.currentTarget).data('id'));
if (!line_id) {
return;
}
var values = {
'product_id': this.lunch_data[line_id].product_id,
'note': this.lunch_data[line_id].note,
'price': this.lunch_data[line_id].price,
}
// Create new order line and reload view
var order_line_ids = this.field_manager.fields.order_line_ids;
order_line_ids.data_create(values)
.then(function (p) {
order_line_ids.reload_current_view();
}
var categories = _.groupBy(data,function(data1){return data1['supplier'][1];});
return self.$el.html(QWeb.render("lunch_order_widget_previous_orders_list", {'widget': self, 'categories': categories}));
});
},
destroy: function() {
this.monetary.destroy();
this._super();
},
is_false: function() {
return false;
);
},
});
core.form_widget_registry.add('previous_order', LunchPreviousOrdersWidget);
return LunchPreviousOrdersWidget;
});
-1
View File
@@ -4,7 +4,6 @@
width: 100%;
.o_lunch_vignette {
.clearfix();
padding: 5px 0;
+ .o_lunch_vignette {
+14 -10
View File
@@ -1,26 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<div t-name="lunch_order_widget_no_previous_order" class="col-md-12">
<div t-name="LunchPreviousOrdersWidgetNoOrder" class="col-md-12">
<h3>This is the first time you order a meal</h3>
<p class="text-muted">Select a product and put your order comments on the note.</p>
<p class="text-muted">Your favorite meals will be created based on your last orders.</p>
<p class="text-muted">Don't forget the alerts displayed in the reddish area</p>
</div>
<t t-name="lunch_order_widget_previous_orders_list">
<div t-foreach="categories" t-as="product_category" class="col-sm-4">
<h3><t t-esc="product_category"/></h3>
<div t-foreach='categories[product_category]' t-as='product' class="o_lunch_vignette">
<button type="button" class="pull-right o_add_button oe_edit_only oe_link" t-att-data-id="product.id">
<t t-name="LunchPreviousOrdersWidgetList">
<div t-foreach="categories" t-as="supplier" class="col-md-4">
<h3><t t-esc="supplier"/></h3>
<div t-foreach='categories[supplier]' t-as='order' class="o_lunch_vignette">
<button type="button" class="pull-right o_add_button oe_edit_only oe_link" t-att-data-id="order.line_id">
<span class="fa fa-plus-square"></span>
<span>Add</span>
</button>
<div class="o_lunch_text">
<t t-esc="product.product_id[1]"/>
<div>
<t t-esc="order.product_name"/>
<span class="badge">
<t t-esc="widget.monetary.format_value(product.price)"/> <t t-esc="product.currency_id[1]"/>
<t t-if="order.position === 'before'"><t t-esc="order.currency"/></t>
<span class="o_lunch_price"><t t-esc="order.price_format"></t></span>
<t t-if="order.position === 'after'"><t t-esc="order.currency"/></t>
</span>
</div>
<div class="text-muted"><t t-if="product.note != false" t-esc="product.note"/></div>
<div class="text-muted">
<t t-if="order.note != false" t-esc="order.note"/>
</div>
</div>
</div>
</t>
+1 -1
View File
@@ -377,7 +377,7 @@
</group>
<div>
<field name='previous_order_ids' widget='previous_order'/>
<field name='previous_order_widget' widget='previous_order' class='o_lunch_last_orders'/>
</div>
<separator string='Select your order'/>