Revert "[IMP] lunch: reintroduce lunch_alerts, change display of wizard"

This reverts commit 6f5dc5733f.
This commit is contained in:
Yannick Tivisse
2019-01-08 13:10:55 +01:00
parent 8ed2a7e68a
commit 3729ebf34d
19 changed files with 143 additions and 399 deletions
-1
View File
@@ -28,7 +28,6 @@ If you want to save your employees' time and avoid them to always have coins in
'report/lunch_order_templates.xml',
'views/lunch_templates.xml',
'wizard/lunch_line_wizard_views.xml',
'views/lunch_alert_views.xml',
'views/lunch_cashmove_views.xml',
'views/lunch_orders_views.xml',
'views/lunch_product_views.xml',
-1
View File
@@ -17,7 +17,6 @@ class LunchController(http.Controller):
'userimage': '/web/image?model=res.users&id=%s&field=image_small' % user.id,
'is_manager': request.env.user.has_group('lunch.group_lunch_manager'),
'users': request.env['res.users'].search_read([('groups_id', 'not in', [request.env.ref('base.group_portal').id])], ['name']),
'alerts': request.env['lunch.alert'].search_read([('available_today', '=', True)], ['message'])
}
order = self._get_current_order(user.id)
+3 -7
View File
@@ -285,15 +285,11 @@
<field name="image" type="base64" file="lunch/static/img/napoli.png"/>
</record>
<record model="lunch.topping.type" id="type_garniture">
<field name="name">Garniture</field>
</record>
<record model="lunch.topping" id="product_olives">
<record model="lunch.product" id="product_olives">
<field name="name">Olives</field>
<field name="price">0.30</field>
<field name="category_id" ref="categ_pizza"/>
<field name="type_id" ref="type_garniture"/>
<field name="supplier_id" eval="str(ref('supplier_pizza_inn'))"/>
<field name="is_topping" eval="True"/>
</record>
<record model="lunch.product" id="product_4formaggi">
-1
View File
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from . import lunch_alert
from . import lunch_cashmove
from . import lunch_order
from . import lunch_product
-115
View File
@@ -1,115 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import math
import pytz
from datetime import datetime, time
from odoo import api, fields, models
from odoo.osv import expression
from odoo.tools import float_round
WEEKDAY_TO_NAME = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
def float_to_time(hours, tz=None):
""" Convert a number of hours into a time object. """
if hours == 24.0:
return time.max
fractional, integral = math.modf(hours)
res = time(int(integral), int(float_round(60 * fractional, precision_digits=0)), 0)
if tz:
res = res.replace(tzinfo=pytz.timezone(tz))
return res
def time_to_float(t):
return float_round(t.hour + t.minute/60 + t.second/3600, precision_digits=2)
class LunchAlert(models.Model):
""" Alerts to display during a lunch order. An alert can be specific to a
given day, weekly or daily. The alert is displayed from start to end hour. """
_name = 'lunch.alert'
_description = 'Lunch Alert'
_rec_name = 'message'
message = fields.Text('Message', required=True)
recurrency = fields.Selection([('once', 'Specific Day'), ('reccurent', 'Reccurent')], 'Recurrency', default='once')
recurrency_from = fields.Float('From', default=7)
recurrency_to = fields.Float('To', default=23)
recurrency_date = fields.Date('Day', default=fields.Date.today())
recurrency_date_from = fields.Datetime('from', compute='_compute_recurrency_date_from', store=True)
recurrency_date_to = fields.Datetime('to', compute='_compute_recurrency_date_to', store=True)
recurrency_monday = fields.Boolean('Monday')
recurrency_tuesday = fields.Boolean('Tuesday')
recurrency_wednesday = fields.Boolean('Wednesday')
recurrency_thursday = fields.Boolean('Thursday')
recurrency_friday = fields.Boolean('Friday')
recurrency_saturday = fields.Boolean('Saturday')
recurrency_sunday = fields.Boolean('Sunday')
available_today = fields.Boolean('This is True when if the supplier is available today',
compute='_compute_available_today', search='_search_available_today')
@api.depends('recurrency_date', 'recurrency_from')
def _compute_recurrency_date_from(self):
for alert in self:
if alert.recurrency_date and alert.recurrency_from:
alert.recurrency_date_from = datetime.combine(alert.recurrency_date, float_to_time(alert.recurrency_from))
@api.depends('recurrency_date', 'recurrency_to')
def _compute_recurrency_date_to(self):
for alert in self:
if alert.recurrency_date and alert.recurrency_to:
alert.recurrency_date_to = datetime.combine(alert.recurrency_date, float_to_time(alert.recurrency_to))
@api.depends('recurrency', 'recurrency_date', 'recurrency_from', 'recurrency_to', 'recurrency_monday',
'recurrency_tuesday', 'recurrency_wednesday', 'recurrency_thursday',
'recurrency_friday', 'recurrency_saturday', 'recurrency_sunday')
def _compute_available_today(self):
now = fields.Datetime.now()
for alert in self:
time_from = float_to_time(alert.recurrency_from)
time_to = float_to_time(alert.recurrency_to)
if alert.recurrency == 'once':
alert.available_today = (alert.recurrency_date_from <= now <= alert.recurrency_date_to)
else:
fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()])
alert.available_today = alert[fieldname] and (time_from <= now.time() <= time_to)
def _search_available_today(self, operator, value):
if (not operator in ['=', '!=']) or (not value in [True, False]):
return []
searching_for_true = (operator == '=' and value) or (operator == '!=' and not value)
now = fields.Datetime.now()
float_now = time_to_float(now.time())
fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()])
if searching_for_true:
specific = expression.AND([
[('recurrency', '=', 'once')],
[('recurrency_date_from', '<=', now)],
[('recurrency_date_to', '>=', now)]
])
else:
specific = expression.AND([
[('recurrency', '=', 'once')],
expression.OR([
[('recurrency_date_from', '>=', now)],
[('recurrency_date_to', '<=', now)]
])
])
recurrence = expression.AND([
[(fieldname, operator, value)],
[('recurrency_from', '<=' if searching_for_true else '>=', float_now)],
[('recurrency_to', '>=' if searching_for_true else '<=', float_now)]
])
return expression.OR([specific, recurrence])
+3 -3
View File
@@ -123,8 +123,8 @@ class LunchOrderLine(models.Model):
name = fields.Char(related='product_id.name', string="Product Name", readonly=True)
order_id = fields.Many2one('lunch.order', 'Order', ondelete='cascade', required=True)
topping_ids = fields.Many2many('lunch.topping', string='Toppings')
product_id = fields.Many2one('lunch.product', string="Product", required=True)
topping_ids = fields.Many2many('lunch.product', string='Toppings')
product_id = fields.Many2one('lunch.product', string="Product", domain=[('is_topping', '=', False)], required=True)
category_id = fields.Many2one('lunch.product.category', string='Product Category',
related='product_id.category_id', readonly=True, store=True)
date = fields.Date(string='Date', related='order_id.date', readonly=True, store=True)
@@ -147,7 +147,7 @@ class LunchOrderLine(models.Model):
@api.depends('topping_ids', 'product_id', 'quantity')
def _compute_total_price(self):
for line in self:
line.price = line.quantity * (line.product_id.price + sum(line.topping_ids.mapped('price')))
line.price = line.quantity * sum(product.price for product in line.product_id | line.topping_ids)
def update_quantity(self, increment):
for line in self:
+2 -32
View File
@@ -14,37 +14,6 @@ class LunchProductCategory(models.Model):
_description = 'Lunch Product Category'
name = fields.Char('Product Category', required=True)
topping_ids = fields.One2many('lunch.topping', 'category_id')
class LunchToppingType(models.Model):
""""""
_name = 'lunch.topping.type'
_description = 'Lunch Topping Type'
name = fields.Char('Name', required=True)
class LunchTopping(models.Model):
""""""
_name = 'lunch.topping'
_description = 'Lunch Toppings'
name = fields.Char('Name', required=True)
price = fields.Float('Price', digits=dp.get_precision('Account'), required=True)
category_id = fields.Many2one('lunch.product.category')
type_id = fields.Many2one('lunch.topping.type')
def name_get(self):
currency_id = self.env.user.company_id.currency_id
res = dict(super(LunchTopping, self).name_get())
for topping in self:
if currency_id.position == 'before':
price = '%s %s' % (currency_id.symbol, topping.price)
else:
price = '%s %s' % (topping.price, currency_id.symbol)
res[topping.id] = '%s %s' % (topping.name, price)
return list(res.items())
class LunchProduct(models.Model):
@@ -53,11 +22,12 @@ class LunchProduct(models.Model):
_description = 'Lunch Product'
name = fields.Char('Name', required=True)
category_id = fields.Many2one('lunch.product.category', 'Product Category', required=True)
category_id = fields.Many2one('lunch.product.category', 'Product Category')
description = fields.Text('Description')
price = fields.Float('Price', digits=dp.get_precision('Account'), required=True)
supplier_id = fields.Many2one('lunch.supplier', 'Vendor', required=True)
active = fields.Boolean(default=True)
is_topping = fields.Boolean("This product is an extra garniture")
# image: all image fields are base64 encoded and PIL-supported
image = fields.Binary(
+9 -12
View File
@@ -49,9 +49,6 @@ class LunchSupplier(models.Model):
vat = fields.Char(related='partner_id.vat')
responsible_id = fields.Many2one('res.users', string="Responsible", domain=lambda self: [('groups_id', 'in', self.env.ref('lunch.group_lunch_manager').id)],
help="This is used to set a responsible for this particular vendor")
image = fields.Binary(related='partner_id.image', readonly=False)
image_medium = fields.Binary(related='partner_id.image_medium', readonly=False)
image_small = fields.Binary(related='partner_id.image_small', readonly=False)
@@ -63,17 +60,17 @@ class LunchSupplier(models.Model):
automatic_email_send = fields.Boolean('Automatic Email Sending')
automatic_email_time = fields.Float('Hour')
recurrency = fields.Selection([('once', 'Specific Day'), ('reccurent', 'Reccurent')], 'Recurrency', default='reccurent')
recurrency_from = fields.Float('From', default=7)
recurrency_to = fields.Float('To', default=23)
recurrency = fields.Selection([('once', 'Specific Day'), ('reccurent', 'Reccurent')], 'Recurrency', default='once')
recurrency_from = fields.Float('From')
recurrency_to = fields.Float('To')
recurrency_date = fields.Date('Day', default=fields.Date.today())
recurrency_date_from = fields.Datetime('from', compute='_compute_recurrency_date_from', store=True)
recurrency_date_to = fields.Datetime('to', compute='_compute_recurrency_date_to', store=True)
recurrency_monday = fields.Boolean('Monday', default=True)
recurrency_tuesday = fields.Boolean('Tuesday', default=True)
recurrency_wednesday = fields.Boolean('Wednesday', default=True)
recurrency_thursday = fields.Boolean('Thursday', default=True)
recurrency_friday = fields.Boolean('Friday', default=True)
recurrency_monday = fields.Boolean('Monday')
recurrency_tuesday = fields.Boolean('Tuesday')
recurrency_wednesday = fields.Boolean('Wednesday')
recurrency_thursday = fields.Boolean('Thursday')
recurrency_friday = fields.Boolean('Friday')
recurrency_saturday = fields.Boolean('Saturday')
recurrency_sunday = fields.Boolean('Sunday')
@@ -145,7 +142,7 @@ class LunchSupplier(models.Model):
time_to = float_to_time(supplier.recurrency_to)
if supplier.recurrency == 'once':
supplier.available_today = (supplier.recurrency_date_from <= now <= supplier.recurrency_date_to)
supplier.available_today = (supplier.reccurrency_date_from <= now <= supplier.reccurrency_date_to)
else:
fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()])
supplier.available_today = supplier[fieldname] and (time_from <= now.time() <= time_to)
@@ -11,10 +11,3 @@ product_user,"Product user",model_lunch_product,group_lunch_user,1,0,0,0
product_category_user,"Product category user",model_lunch_product_category,group_lunch_user,1,0,0,0
lunch_supplier_user,"Lunch Supplier User Rights",model_lunch_supplier,group_lunch_user,1,0,0,0
lunch_supplier_manager,"Lunch Supplier Manager Rights",model_lunch_supplier,group_lunch_manager,1,1,1,1
lunch_alert_access,access_lunch_alert_user,model_lunch_alert,base.group_user,1,0,0,0
lunch_alert_user,access_lunch_alert_lunch_user,model_lunch_alert,group_lunch_user,1,1,1,1
lunch_alert_manager,access_lunch_alert_manager,model_lunch_alert,group_lunch_manager,1,1,1,1
lunch_topping_type_user,access_lunch_topping_type,model_lunch_topping_type,base.group_user,1,0,0,0
lunch_topping_type_manager,access_lunch_topping_type,model_lunch_topping_type,group_lunch_manager,1,1,1,1
lunch_topping_user,access_lunch_topping,model_lunch_topping,base.group_user,1,0,0,0
lunch_topping_manager,access_lunch_topping,model_lunch_topping,group_lunch_manager,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
11 product_category_user Product category user model_lunch_product_category group_lunch_user 1 0 0 0
12 lunch_supplier_user Lunch Supplier User Rights model_lunch_supplier group_lunch_user 1 0 0 0
13 lunch_supplier_manager Lunch Supplier Manager Rights model_lunch_supplier group_lunch_manager 1 1 1 1
lunch_alert_access access_lunch_alert_user model_lunch_alert base.group_user 1 0 0 0
lunch_alert_user access_lunch_alert_lunch_user model_lunch_alert group_lunch_user 1 1 1 1
lunch_alert_manager access_lunch_alert_manager model_lunch_alert group_lunch_manager 1 1 1 1
lunch_topping_type_user access_lunch_topping_type model_lunch_topping_type base.group_user 1 0 0 0
lunch_topping_type_manager access_lunch_topping_type model_lunch_topping_type group_lunch_manager 1 1 1 1
lunch_topping_user access_lunch_topping model_lunch_topping base.group_user 1 0 0 0
lunch_topping_manager access_lunch_topping model_lunch_topping group_lunch_manager 1 1 1 1
@@ -5,17 +5,18 @@
.o_lunch_widget {
display: flex;
overflow: auto;
border-bottom: 1px solid #CED4DA;
background-color: white;
min-height: 90px;
overflow-y: visible;
max-height: 90px;
.o_lunch_widget_info {
padding: 5px 12px;
margin: 4px 8px;
width: 300px;
flex: 1 1 auto;
overflow-y: visible;
overflow-y: auto;
.o_lunch_ordered {
color: white;
+91 -98
View File
@@ -1,108 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<div t-name="LunchKanbanWidget">
<div class="o_lunch_widget">
<div class="o_lunch_widget_info d-flex flex-row">
<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>
<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 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>
</span>
<span>
<a class="o_add_money" href="#">Add money</a>
</span>
</div>
</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 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-foreach="widget.data.alerts" t-as="alert">
<div class="alert alert-danger" role="alert">
<t t-esc="alert.message"/>
</div>
</t>
<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">
@@ -49,8 +49,7 @@ QUnit.module('Views', {
state: 'new',
lines: [
{id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
],
alerts: [],
]
});
} else if (route.startsWith('data:image/png;base64,')) {
return $.when();
@@ -112,8 +111,7 @@ QUnit.module('Views', {
state: state,
lines: [
{id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
],
alerts: [],
]
});
} else if (route === '/lunch/payment_message') {
return $.when({message: 'Hello'});
@@ -184,8 +182,7 @@ QUnit.module('Views', {
state: 'new',
lines: [
{id: 1, product: ['Pizza Italiana', 7.4], toppings: [], quantity: 1.0, price: 7.4}
],
alerts: [],
]
});
} else if (route.startsWith('data:image/png;base64,')) {
return $.when();
+3 -7
View File
@@ -67,13 +67,9 @@ class TestsCommon(common.TransactionCase):
'supplier_id': self.supplier_coin_gourmand.id,
})
self.garniture_type = self.env['lunch.topping.type'].create({
'name': 'Graniture',
})
self.topping_olives = self.env['lunch.topping'].create({
self.topping_olives = self.env['lunch.product'].create({
'name': 'Olives',
'price': 0.3,
'category_id': self.category_pizza.id,
'type_id': self.garniture_type.id,
'supplier_id': self.supplier_pizza_inn.id,
'is_topping': True,
})
-60
View File
@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="lunch_alert_view_search" model="ir.ui.view">
<field name="name">lunch.alert.search</field>
<field name="model">lunch.alert</field>
<field name="arch" type="xml">
<search string="Search">
<field name="message"/>
<filter name="inactive" string="Currently inactive" domain="[('available_today','=',False)]"/>
</search>
</field>
</record>
<record id="lunch_alert_view_tree" model="ir.ui.view">
<field name="name">lunch.alert.tree</field>
<field name="model">lunch.alert</field>
<field name="arch" type="xml">
<tree>
<field name="message"/>
<field name="recurrency"/>
<field name='recurrency_from' widget='float_time'/>
<field name='recurrency_to' widget='float_time'/>
</tree>
</field>
</record>
<record id="lunch_alert_view_form" model="ir.ui.view">
<field name="name">lunch.alert.form</field>
<field name="model">lunch.alert</field>
<field name="arch" type="xml">
<form string="alert form">
<sheet>
<group>
<field name="recurrency"/>
<field name="recurrency_date" attrs="{'invisible': [('recurrency', '!=', 'once')]}"/>
<field name="recurrency_monday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_tuesday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_wednesday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_thursday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_friday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_saturday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_sunday" attrs="{'invisible': [('recurrency', '!=', 'reccurent')]}"/>
<field name="recurrency_from" widget="float_time"/>
<field name="recurrency_to" widget="float_time"/>
</group>
<label for='message'/>
<field name="message"/>
</sheet>
</form>
</field>
</record>
<record id="lunch_alert_action" model="ir.actions.act_window">
<field name="name">Lunch Alerts</field>
<field name="res_model">lunch.alert</field>
<field name="search_view_id" ref="lunch_alert_view_search"/>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="lunch_alert_view_tree"/>
</record>
</odoo>
+11 -15
View File
@@ -11,8 +11,8 @@
<field name="description"/>
<filter name="inactive" string="Archived" domain="[('active','=',False)]"/>
<group expand="0" string="Group By">
<filter name="group_by_supplier" string="Vendor" context="{'group_by': 'supplier_id'}"/>
<filter name="group_by_category" string="Product Category" context="{'group_by': 'category_id'}"/>
<filter name="supplier" string="Vendor" context="{'group_by': 'supplier_id'}"/>
<filter name="category" string="Product Category" context="{'group_by': 'category_id'}"/>
</group>
</search>
</field>
@@ -48,8 +48,12 @@
<field name="image" widget="image" class="oe_avatar" options="{'preview_image': 'image_medium'}"/>
<label for="name"/>
<field name='name'/>
<div>
<field name="is_topping"/>
<label for="is_topping"/>
</div>
<group>
<field name='category_id'/>
<field name='category_id' attrs="{'invisible': [('is_topping', '=', True)], 'required': [('is_topping', '=', False)]}"/>
<field name='supplier_id'/>
<field name='price'/>
</group>
@@ -68,7 +72,7 @@
<field name="name">lunch.product.kanban</field>
<field name="model">lunch.product</field>
<field name="arch" type="xml">
<kanban js_class="lunch_kanban" create="0" edit="0" group_create="0" group_edit="0" group_delete="0" class="o_kanban_mobile">
<kanban js_class="lunch_kanban" create="0" class="o_kanban_mobile">
<field name="id"/>
<field name="name"/>
<field name="category_id"/>
@@ -111,7 +115,7 @@
<field name="name">Product category Tree</field>
<field name="model">lunch.product.category</field>
<field name="arch" type="xml">
<tree string="Products List">
<tree string="Products List" editable="bottom">
<field name='name' string="Product Category: "/>
</tree>
</field>
@@ -124,14 +128,7 @@
<form string="Products Form">
<sheet>
<group>
<field name="name" string="Product Category: "/>
<field name="topping_ids">
<tree editable="bottom">
<field name="type_id"/>
<field name="name"/>
<field name="price"/>
</tree>
</field>
<field name='name' string="Product Category: "/>
</group>
</sheet>
</form>
@@ -155,8 +152,7 @@
<field name="name">Order</field>
<field name="res_model">lunch.product</field>
<field name="view_mode">kanban</field>
<field name="search_view_id" ref="lunch_product_view_search"/>
<field name="domain">[('supplier_id.available_today', '=', True)]</field>
<field name="domain">[('is_topping', '=', False), ('supplier_id.available_today', '=', True)]</field>
</record>
<record id="lunch_product_category_action" model="ir.actions.act_window">
@@ -40,9 +40,6 @@
<field name="email"/>
<field name="phone"/>
</group>
<group>
<field name="responsible_id"/>
</group>
<notebook colspan="4">
<page string="Availability">
<group>
-1
View File
@@ -18,7 +18,6 @@
<menuitem name="Vendors" parent="menu_lunch_config" id="lunch_vendors_menu" action="lunch_vendors_action" sequence="1"/>
<menuitem name="Products" parent="menu_lunch_config" id="lunch_product_menu" action="lunch_product_action" sequence="2"/>
<menuitem name="Product Categories" parent="menu_lunch_config" id="lunch_product_category_menu" action="lunch_product_category_action" sequence="3"/>
<menuitem name="Alerts" parent="menu_lunch_config" id="lunch_alert_menu" action="lunch_alert_action" sequence="4"/>
<record id="action_server_lunch_archive_product" model="ir.actions.server">
+3 -17
View File
@@ -10,20 +10,11 @@ class LunchOrderLineWizard(models.TransientModel):
_name = 'lunch.order.line.temp'
_description = 'Lunch Order Line Temp'
def _default_topping_ids(self):
last_time_ordered = self.env['lunch.order.line'].search([('product_id', '=', self.env.context.get('default_product_id', 0))],
order="date desc", limit=1)
return last_time_ordered.topping_ids
currency_id = fields.Many2one('res.currency', default=lambda self: self.env.user.company_id.currency_id)
product_id = fields.Many2one('lunch.product', string='Product ID')
product_description = fields.Text('Description', related='product_id.description')
product_name = fields.Char('Product', related='product_id.name')
product_category = fields.Many2one('lunch.product.category', related='product_id.category_id')
topping_ids = fields.Many2many('lunch.topping', string="Extra Garniture", domain="[('category_id', '=', product_category)]", default=_default_topping_ids)
available_toppings = fields.Boolean(help='Are toppings available for this product', compute='_compute_available_toppings')
product_supplier = fields.Many2one('lunch.supplier', related='product_id.supplier_id')
topping_ids = fields.Many2many('lunch.product', string="Extra Garniture", domain="[('is_topping', '=', True), ('supplier_id', '=', product_supplier)]")
quantity = fields.Float('Quantity', default=1)
price_total = fields.Float('Total Price', compute='_compute_price_total')
@@ -31,15 +22,10 @@ class LunchOrderLineWizard(models.TransientModel):
user_id = fields.Many2one('res.users', default=lambda self: self.env.user.id)
@api.depends('product_id')
def _compute_available_toppings(self):
for wizard in self:
wizard.available_toppings = bool(wizard.env['lunch.topping'].search_count([('category_id', '=', wizard.product_category.id)]))
@api.depends('product_id', 'topping_ids', 'quantity')
def _compute_price_total(self):
for wizard in self:
wizard.price_total = wizard.quantity * (wizard.product_id.price + sum(wizard.topping_ids.mapped('price')))
wizard.price_total = wizard.quantity * sum(record.price for record in (wizard.product_id | wizard.topping_ids))
def find_current_order(self):
order_id = self.env['lunch.order'].search([('state', '!=', 'cancel'),
+12 -11
View File
@@ -7,24 +7,25 @@
<field name="model">lunch.order.line.temp</field>
<field name="arch" type="xml">
<form>
<field name="currency_id" invisible="1"/>
<field name="quantity" invisible="1"/>
<field name="product_id" invisible="1"/>
<field name="product_category" invisible="1"/>
<h2 class="d-flex">
<div class="flex-grow-1 pr-5"><field name="product_name"/></div>
<div class="flex-grow-0"><field name="price_total" widget="monetary"/></div>
</h2>
<group>
<field name="available_toppings" invisible="1"/>
<field name="topping_ids" attrs="{'invisible': [('available_toppings', '=', False)]}" widget="many2many_checkboxes"/>
<field name="product_id" invisible="1"/>
<field name="product_supplier" invisible="1"/>
<field name="product_name"/>
<field name="product_description"/>
<field name="topping_ids" widget="many2many_tags"/>
</group>
<group>
<field name="note"/>
</group>
<group>
<field name="quantity"/>
<field name="price_total" widget="monetary"/>
</group>
<footer>
<button name="add_to_cart" string="Add To Cart" type="object" class="oe_highlight"/>
<button string="Discard" special="cancel"/>
</footer>
</form>
</field>