[IMP] lunch: add 'Sent' status
Added a new 'Sent' status, meaning the orders have been made to the supplier. Once an order is 'Sent' it cannot be modified anymore. It's no longer possible to order a product after the automatic email has been sent. closes odoo/odoo#80584 Taskid: 2678064 Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
@@ -18,19 +18,19 @@ class LunchController(http.Controller):
|
||||
|
||||
lines = self._get_current_lines(user)
|
||||
if lines:
|
||||
translated_states = dict(request.env['lunch.order']._fields['state']._description_selection(request.env))
|
||||
lines = [{'id': line.id,
|
||||
'product': (line.product_id.id, line.product_id.name, float_repr(float_round(line.price, 2), 2)),
|
||||
'toppings': [(topping.name, float_repr(float_round(topping.price, 2), 2))
|
||||
for topping in line.topping_ids_1 | line.topping_ids_2 | line.topping_ids_3],
|
||||
'quantity': line.quantity,
|
||||
'price': line.price,
|
||||
'state': line.state, # Only used for _get_state
|
||||
'note': line.note} for line in lines]
|
||||
raw_state, state = self._get_state(lines)
|
||||
'raw_state': line.state,
|
||||
'state': translated_states[line.state],
|
||||
'note': line.note} for line in lines.sorted('date')]
|
||||
infos.update({
|
||||
'total': float_repr(float_round(sum(line['price'] for line in lines), 2), 2),
|
||||
'raw_state': raw_state,
|
||||
'state': state,
|
||||
'raw_state': self._get_state(lines),
|
||||
'lines': lines,
|
||||
})
|
||||
return infos
|
||||
@@ -41,6 +41,7 @@ class LunchController(http.Controller):
|
||||
user = request.env['res.users'].browse(user_id) if user_id else request.env.user
|
||||
|
||||
lines = self._get_current_lines(user)
|
||||
lines = lines.filtered_domain([('state', 'not in', ['sent', 'confirmed'])])
|
||||
lines.action_cancel()
|
||||
lines.unlink()
|
||||
|
||||
@@ -134,10 +135,7 @@ class LunchController(http.Controller):
|
||||
|
||||
eg: [confirmed, confirmed, new] will return ('new', 'To Order')
|
||||
"""
|
||||
states_to_int = {'new': 0, 'ordered': 1, 'confirmed': 2, 'cancelled': 3}
|
||||
int_to_states = ['new', 'ordered', 'confirmed', 'cancelled']
|
||||
translated_states = dict(request.env['lunch.order']._fields['state']._description_selection(request.env))
|
||||
states_to_int = {'new': 0, 'ordered': 1, 'sent': 2, 'confirmed': 3, 'cancelled': 4}
|
||||
int_to_states = ['new', 'ordered', 'sent', 'confirmed', 'cancelled']
|
||||
|
||||
state = int_to_states[min(states_to_int[line['state']] for line in lines)]
|
||||
|
||||
return (state, translated_states[state])
|
||||
return int_to_states[min(states_to_int[line['raw_state']] for line in lines)]
|
||||
|
||||
@@ -23,6 +23,8 @@ class LunchOrder(models.Model):
|
||||
default=fields.Date.context_today)
|
||||
supplier_id = fields.Many2one(
|
||||
string='Vendor', related='product_id.supplier_id', store=True, index=True)
|
||||
available_today = fields.Boolean(related='supplier_id.available_today')
|
||||
order_deadline_passed = fields.Boolean(related='supplier_id.order_deadline_passed')
|
||||
user_id = fields.Many2one('res.users', 'User', readonly=True,
|
||||
states={'new': [('readonly', False)]},
|
||||
default=lambda self: self.env.uid)
|
||||
@@ -31,8 +33,9 @@ class LunchOrder(models.Model):
|
||||
price = fields.Monetary('Total Price', compute='_compute_total_price', readonly=True, store=True)
|
||||
active = fields.Boolean('Active', default=True)
|
||||
state = fields.Selection([('new', 'To Order'),
|
||||
('ordered', 'Ordered'),
|
||||
('confirmed', 'Received'),
|
||||
('ordered', 'Ordered'), # "Internally" ordered
|
||||
('sent', 'Sent'), # Order sent to the supplier
|
||||
('confirmed', 'Received'), # Order received
|
||||
('cancelled', 'Cancelled')],
|
||||
'Status', readonly=True, index=True, default='new')
|
||||
notified = fields.Boolean(default=False)
|
||||
@@ -75,7 +78,7 @@ class LunchOrder(models.Model):
|
||||
def _compute_display_reorder_button(self):
|
||||
show_button = self.env.context.get('show_reorder_button')
|
||||
for order in self:
|
||||
order.display_reorder_button = show_button and order.state == 'confirmed'
|
||||
order.display_reorder_button = show_button and order.state == 'confirmed' and order.supplier_id.available_today
|
||||
|
||||
def init(self):
|
||||
self._cr.execute("""CREATE INDEX IF NOT EXISTS lunch_order_user_product_date ON %s (user_id, product_id, date)"""
|
||||
@@ -124,7 +127,7 @@ class LunchOrder(models.Model):
|
||||
**vals,
|
||||
'toppings': self._extract_toppings(vals),
|
||||
})
|
||||
if lines:
|
||||
if lines.filtered(lambda l: l.state not in ['sent', 'confirmed']):
|
||||
# YTI FIXME This will update multiple lines in the case there are multiple
|
||||
# matching lines which should not happen through the interface
|
||||
lines.update_quantity(1)
|
||||
@@ -187,7 +190,7 @@ class LunchOrder(models.Model):
|
||||
line.display_toppings = ' + '.join(toppings.mapped('name'))
|
||||
|
||||
def update_quantity(self, increment):
|
||||
for line in self.filtered(lambda line: line.state != 'confirmed'):
|
||||
for line in self.filtered(lambda line: line.state not in ['sent', 'confirmed']):
|
||||
if line.quantity <= -increment:
|
||||
# TODO: maybe unlink the order?
|
||||
line.active = False
|
||||
@@ -242,6 +245,9 @@ class LunchOrder(models.Model):
|
||||
def action_reset(self):
|
||||
self.write({'state': 'ordered'})
|
||||
|
||||
def action_send(self):
|
||||
self.state = 'sent'
|
||||
|
||||
def action_notify(self):
|
||||
self -= self.filtered('notified')
|
||||
if not self:
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
import math
|
||||
import pytz
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, time, timedelta
|
||||
from textwrap import dedent
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_round
|
||||
|
||||
@@ -72,6 +73,7 @@ class LunchSupplier(models.Model):
|
||||
available_location_ids = fields.Many2many('lunch.location', string='Location')
|
||||
available_today = fields.Boolean('This is True when if the supplier is available today',
|
||||
compute='_compute_available_today', search='_search_available_today')
|
||||
order_deadline_passed = fields.Boolean(compute='_compute_order_deadline_passed')
|
||||
|
||||
tz = fields.Selection(_tz_get, string='Timezone', required=True, default=lambda self: self.env.user.tz or 'UTC')
|
||||
|
||||
@@ -106,6 +108,9 @@ class LunchSupplier(models.Model):
|
||||
('1_more', 'One or More'),
|
||||
('1', 'Only One')], 'Extra 3 Quantity', default='0_more', required=True)
|
||||
|
||||
show_order_button = fields.Boolean(compute='_compute_buttons')
|
||||
show_confirm_button = fields.Boolean(compute='_compute_buttons')
|
||||
|
||||
_sql_constraints = [
|
||||
('automatic_email_time_range',
|
||||
'CHECK(automatic_email_time >= 0 AND automatic_email_time <= 12)',
|
||||
@@ -215,6 +220,19 @@ class LunchSupplier(models.Model):
|
||||
Product.search([('supplier_id', 'in', inactive_suppliers.ids)]).write({'active': False})
|
||||
return res
|
||||
|
||||
def _get_current_orders(self, state='ordered'):
|
||||
""" Returns today's orders """
|
||||
available_today = self.filtered('available_today')
|
||||
if not available_today:
|
||||
return self.env['lunch.order']
|
||||
|
||||
orders = self.env['lunch.order'].search([
|
||||
('supplier_id', 'in', available_today.ids),
|
||||
('state', '=', state),
|
||||
('date', '=', fields.Date.context_today(self.with_context(tz=self.tz))),
|
||||
], order="user_id, name")
|
||||
return orders
|
||||
|
||||
def _send_auto_email(self):
|
||||
""" Send an email to the supplier with the order of the day """
|
||||
# Called daily by cron
|
||||
@@ -226,11 +244,7 @@ class LunchSupplier(models.Model):
|
||||
if self.send_by != 'mail':
|
||||
raise ValueError("Cannot send an email to this supplier")
|
||||
|
||||
orders = self.env['lunch.order'].search([
|
||||
('supplier_id', '=', self.id),
|
||||
('state', '=', 'ordered'),
|
||||
('date', '=', fields.Date.context_today(self.with_context(tz=self.tz))),
|
||||
], order="user_id, name")
|
||||
orders = self._get_current_orders()
|
||||
if not orders:
|
||||
return
|
||||
|
||||
@@ -265,7 +279,7 @@ class LunchSupplier(models.Model):
|
||||
order=order, lines=email_orders, sites=email_sites
|
||||
).send_mail(self.id)
|
||||
|
||||
orders.action_confirm()
|
||||
orders.action_send()
|
||||
|
||||
@api.depends('recurrency_end_date', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun')
|
||||
def _compute_available_today(self):
|
||||
@@ -274,11 +288,27 @@ class LunchSupplier(models.Model):
|
||||
for supplier in self:
|
||||
now = now.astimezone(pytz.timezone(supplier.tz))
|
||||
|
||||
if supplier.recurrency_end_date and now.date() >= supplier.recurrency_end_date:
|
||||
supplier.available_today = False
|
||||
supplier.available_today = supplier._available_on_date(now)
|
||||
|
||||
def _available_on_date(self, date):
|
||||
self.ensure_one()
|
||||
|
||||
fieldname = WEEKDAY_TO_NAME[date.weekday()]
|
||||
return not (self.recurrency_end_date and date.date() >= self.recurrency_end_date) and self[fieldname]
|
||||
|
||||
@api.depends('available_today', 'automatic_email_time', 'send_by')
|
||||
def _compute_order_deadline_passed(self):
|
||||
now = fields.Datetime.now().replace(tzinfo=pytz.UTC)
|
||||
|
||||
for supplier in self:
|
||||
if supplier.send_by == 'mail':
|
||||
now = now.astimezone(pytz.timezone(supplier.tz))
|
||||
email_time = pytz.timezone(supplier.tz).localize(datetime.combine(
|
||||
fields.Date.context_today(supplier),
|
||||
float_to_time(supplier.automatic_email_time, supplier.moment)))
|
||||
supplier.order_deadline_passed = supplier.available_today and now > email_time
|
||||
else:
|
||||
fieldname = WEEKDAY_TO_NAME[now.weekday()]
|
||||
supplier.available_today = supplier[fieldname]
|
||||
supplier.order_deadline_passed = not supplier.available_today
|
||||
|
||||
def _search_available_today(self, operator, value):
|
||||
if (not operator in ['=', '!=']) or (not value in [True, False]):
|
||||
@@ -298,3 +328,52 @@ class LunchSupplier(models.Model):
|
||||
recurrency_domain,
|
||||
[(fieldname, operator, value)]
|
||||
])
|
||||
|
||||
def _compute_buttons(self):
|
||||
self.env.cr.execute("""
|
||||
SELECT supplier_id, state, COUNT(*)
|
||||
FROM lunch_order
|
||||
WHERE supplier_id IN %s
|
||||
AND state in ('ordered', 'sent')
|
||||
AND date = %s
|
||||
AND active
|
||||
GROUP BY supplier_id, state
|
||||
""", (tuple(self.ids), fields.Date.context_today(self)))
|
||||
supplier_orders = defaultdict(dict)
|
||||
for order in self.env.cr.fetchall():
|
||||
supplier_orders[order[0]][order[1]] = order[2]
|
||||
for supplier in self:
|
||||
supplier.show_order_button = supplier_orders[supplier.id].get('ordered', False)
|
||||
supplier.show_confirm_button = supplier_orders[supplier.id].get('sent', False)
|
||||
|
||||
def action_send_orders(self):
|
||||
no_auto_mail = self.filtered(lambda s: s.send_by != 'mail')
|
||||
|
||||
for supplier in self - no_auto_mail:
|
||||
supplier._send_auto_email()
|
||||
orders = no_auto_mail._get_current_orders()
|
||||
orders.action_send()
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'type': 'success',
|
||||
'message': _('The orders have been sent!'),
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
|
||||
def action_confirm_orders(self):
|
||||
orders = self._get_current_orders(state='sent')
|
||||
orders.action_confirm()
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'type': 'success',
|
||||
'message': _('The orders have been confirmed!'),
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ class LunchOrder(models.Model):
|
||||
('note', populate.constant('lunch_note_{counter}')),
|
||||
('company_id', populate.randomize(company_ids)),
|
||||
('quantity', populate.randint(0, 10)),
|
||||
('date', populate.randdatetime(relative_before=relativedelta(months=-3), relative_after=relativedelta(months=3))),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -30,28 +30,26 @@
|
||||
</div>
|
||||
<div class="o_lunch_widget_info col-12 col-md-4 card border-0">
|
||||
<t t-if="!_.isEmpty(widget.lines)">
|
||||
<t t-if="widget.raw_state == 'ordered'">
|
||||
<t t-set="state_class" t-value="'badge-warning o_lunch_ordered'"/>
|
||||
</t>
|
||||
<t t-else="widget.raw_state == 'confirmed'">
|
||||
<t t-set="state_class" t-value="'badge-success o_lunch_confirmed'"/>
|
||||
</t>
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">
|
||||
Your order
|
||||
<button t-if="widget.raw_state != 'confirmed'" class="btn btn-sm btn-icon btn-link fa fa-trash o_lunch_widget_unlink"/>
|
||||
<span t-if="widget.raw_state != 'new'" t-esc="widget.state" t-attf-class="badge badge-pill {{ state_class }}"/>
|
||||
</h4>
|
||||
<ul class="list-unstyled o_lunch_widget_lines">
|
||||
<t t-set="states_mapping" t-value="{'new': 'warning', 'confirmed': 'success', 'sent': 'info', 'ordered': 'danger'}" />
|
||||
<li t-foreach="widget.lines" t-as="line" t-key="line_index">
|
||||
<t t-set="can_modify" t-value="!['sent', 'confirmed'].includes(line.raw_state)" />
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="flex-grow-0 flex-shrink-0 o_lunch_product_quantity">
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-minus-circle o_remove_product" t-if="widget.raw_state != 'confirmed'" t-attf-data-id="{{ line.id }}"/>
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-minus-circle o_remove_product" t-if="can_modify" t-attf-data-id="{{ line.id }}"/>
|
||||
<span t-esc="line.quantity"/>
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-plus-circle o_add_product" t-if="widget.raw_state != 'confirmed'" t-attf-data-id="{{ line.id }}"/>
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-plus-circle o_add_product" t-if="can_modify" t-attf-data-id="{{ line.id }}"/>
|
||||
</div>
|
||||
<div class="flex-grow-1 pl-2">
|
||||
<button t-esc="line.product[1]" class="btn btn-link o_lunch_open_wizard" t-attf-data-product-id="{{ line.product[0] }}" t-attf-data-id="{{ line.id }}"/>
|
||||
<button t-if="can_modify" t-esc="line.product[1]" t-attf-class="btn btn-link o_lunch_open_wizard" t-attf-data-product-id="{{ line.product[0] }}" t-attf-data-id="{{ line.id }}"/>
|
||||
<t t-else="" t-esc="line.product[1]" />
|
||||
<t t-set="state_pill" t-value="states_mapping[line.raw_state]" />
|
||||
<span t-esc="line.state" t-attf-class="badge badge-pill badge-{{ state_pill }}" />
|
||||
</div>
|
||||
<div class="flex-grow-0">
|
||||
<t t-call="currency_field">
|
||||
|
||||
@@ -414,7 +414,7 @@ QUnit.module('LunchKanbanView', {
|
||||
});
|
||||
|
||||
QUnit.test('ordered cart', async function (assert) {
|
||||
assert.expect(15);
|
||||
assert.expect(13);
|
||||
|
||||
const kanban = await createLunchView({
|
||||
View: LunchKanbanView,
|
||||
@@ -438,6 +438,7 @@ QUnit.module('LunchKanbanView', {
|
||||
product: [1, "Tuna sandwich", "3.00"],
|
||||
toppings: [],
|
||||
quantity: 1.0,
|
||||
raw_state: 'ordered',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -457,10 +458,6 @@ QUnit.module('LunchKanbanView', {
|
||||
|
||||
assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_unlink',
|
||||
"should have a button to clear the order");
|
||||
assert.containsOnce($widgetSecondColumn, '.badge.badge-warning.o_lunch_ordered',
|
||||
"should have an ordered state badge");
|
||||
assert.strictEqual($widgetSecondColumn.find('.o_lunch_ordered').text().trim(), "Ordered",
|
||||
"should have 'Ordered' in the state badge");
|
||||
|
||||
assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li',
|
||||
"should have 1 order line");
|
||||
@@ -490,7 +487,7 @@ QUnit.module('LunchKanbanView', {
|
||||
});
|
||||
|
||||
QUnit.test('confirmed cart', async function (assert) {
|
||||
assert.expect(15);
|
||||
assert.expect(12);
|
||||
|
||||
const kanban = await createLunchView({
|
||||
View: LunchKanbanView,
|
||||
@@ -514,6 +511,8 @@ QUnit.module('LunchKanbanView', {
|
||||
product: [1, "Tuna sandwich", "3.00"],
|
||||
toppings: [],
|
||||
quantity: 1.0,
|
||||
raw_state: 'confirmed',
|
||||
state: 'Confirmed',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -533,10 +532,6 @@ QUnit.module('LunchKanbanView', {
|
||||
|
||||
assert.containsNone($widgetSecondColumn, '.o_lunch_widget_unlink',
|
||||
"shouldn't have a button to clear the order");
|
||||
assert.containsOnce($widgetSecondColumn, '.badge.badge-success.o_lunch_confirmed',
|
||||
"should have a confirmed state badge");
|
||||
assert.strictEqual($widgetSecondColumn.find('.o_lunch_confirmed').text().trim(), "Received",
|
||||
"should have 'Received' in the state badge");
|
||||
|
||||
assert.containsOnce($widgetSecondColumn, '.o_lunch_widget_lines > li',
|
||||
"should have 1 order line");
|
||||
@@ -550,10 +545,8 @@ QUnit.module('LunchKanbanView', {
|
||||
"should have the line's quantity");
|
||||
assert.strictEqual($firstLine.find('.o_lunch_product_quantity').text().trim(), "1",
|
||||
"should have 1 as the line's quantity");
|
||||
assert.containsOnce($firstLine, '.o_lunch_open_wizard',
|
||||
"should have the line's product name to open the wizard");
|
||||
assert.strictEqual($firstLine.find('.o_lunch_open_wizard').text().trim(), "Tuna sandwich",
|
||||
"should have 'Tuna sandwich' as the line's product name");
|
||||
assert.containsNone($firstLine, '.o_lunch_open_wizard',
|
||||
"shouldn't have the line's product name to open the wizard");
|
||||
assert.containsOnce($firstLine, '.o_field_monetary',
|
||||
"should have the line's amount");
|
||||
assert.strictEqual($firstLine.find('.o_field_monetary').text().trim(), "3.00€",
|
||||
|
||||
@@ -95,7 +95,7 @@ env['lunch.supplier'].browse([{self.supplier_kothai.id}])._send_auto_email()""")
|
||||
|
||||
self.supplier_pizza_inn._send_auto_email()
|
||||
|
||||
assert line.state == 'confirmed'
|
||||
assert line.state == 'sent'
|
||||
|
||||
line = self.env['lunch.order'].create({
|
||||
'product_id': self.product_pizza.id,
|
||||
@@ -115,21 +115,21 @@ env['lunch.supplier'].browse([{self.supplier_kothai.id}])._send_auto_email()""")
|
||||
|
||||
self.supplier_pizza_inn._send_auto_email()
|
||||
|
||||
assert line.state == 'confirmed'
|
||||
assert line.state == 'sent'
|
||||
assert line2.state == 'ordered'
|
||||
|
||||
line_1 = self.env['lunch.order'].create({
|
||||
'product_id': self.product_pizza.id,
|
||||
'quantity': 2,
|
||||
'date': self.monday_1pm.date(),
|
||||
'supplier_id': self.product_pizza.id,
|
||||
'supplier_id': self.supplier_pizza_inn.id,
|
||||
})
|
||||
|
||||
line_2 = self.env['lunch.order'].create({
|
||||
'product_id': self.product_pizza.id,
|
||||
'topping_ids_1': [(6, 0, [self.topping_olives.id])],
|
||||
'date': self.monday_1pm.date(),
|
||||
'supplier_id': self.product_pizza.id,
|
||||
'supplier_id': self.supplier_pizza_inn.id,
|
||||
})
|
||||
|
||||
line_3 = self.env['lunch.order'].create({
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<field name="name">lunch.order.tree</field>
|
||||
<field name="model">lunch.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Order lines Tree" create="false" edit="false" decoration-muted="state == 'cancelled'" class="o_lunch_list">
|
||||
<tree string="Order lines Tree" create="false" edit="false" decoration-muted="state == 'cancelled'" class="o_lunch_list" expand="1">
|
||||
<header>
|
||||
<button name="action_confirm" type="object" string="Receive"/>
|
||||
</header>
|
||||
@@ -43,15 +43,21 @@
|
||||
<field name="lunch_location_id"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name='price' sum="Total" string="Price" widget="monetary"/>
|
||||
<field name='state'/>
|
||||
<field name='state' widget="badge" decoration-warning="state == 'new'" decoration-success="state == 'confirmed'" decoration-info="state == 'sent'" decoration-danger="state == 'ordered'"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="display_reorder_button" invisible="1"/>
|
||||
<field name="notified" invisible="1"/>
|
||||
<button name="action_reorder" string="Re-order" type="object" icon="fa-history" attrs="{'invisible': [('display_reorder_button', '=', False)]}" groups="lunch.group_lunch_user"/>
|
||||
<button name="action_confirm" string="Confirm" type="object" icon="fa-check" attrs="{'invisible': [('state', '!=', 'ordered')]}" groups="lunch.group_lunch_manager"/>
|
||||
<button name="action_confirm" string="Confirm" type="object" icon="fa-check" attrs="{'invisible': [('state', '!=', 'sent')]}" groups="lunch.group_lunch_manager"/>
|
||||
<button name="action_cancel" string="Cancel" type="object" icon="fa-times" attrs="{'invisible': [('state', 'in', ['cancelled', 'confirmed'])]}" groups="lunch.group_lunch_manager"/>
|
||||
<button name="action_reset" string="Reset" type="object" icon="fa-undo" attrs="{'invisible': [('state', '!=', 'cancelled')]}" groups="lunch.group_lunch_manager"/>
|
||||
<button name="action_notify" string="Send Notification" type="object" icon="fa-envelope" attrs="{'invisible': ['|', ('state', '!=', 'confirmed'), ('notified', '=', True)]}" groups="lunch.group_lunch_manager"/>
|
||||
<groupby name="supplier_id">
|
||||
<field name="show_order_button" invisible="1" />
|
||||
<field name="show_confirm_button" invisible="1" />
|
||||
<button string="Send Orders" type="object" name="action_send_orders" attrs="{'invisible': [('show_order_button', '=', False)]}"/>
|
||||
<button string="Confirm Orders" type="object" name="action_confirm_orders" attrs="{'invisible': [('show_confirm_button', '=', False)]}"/>
|
||||
</groupby>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -91,13 +97,16 @@
|
||||
</div>
|
||||
<div class="row mt4">
|
||||
<div class="col-6">
|
||||
<a class="btn btn-sm btn-success" role="button" name="action_order" string="Order" type="object" attrs="{'invisible': ['|',('state','=','confirmed'),('state','=','ordered')]}" groups="lunch.group_lunch_manager">
|
||||
<a class="btn btn-sm btn-success" role="button" name="action_order" string="Order" type="object" attrs="{'invisible': [('state', 'in', ['sent', 'ordered', 'confirmed'])]}" groups="lunch.group_lunch_manager">
|
||||
<i class="fa fa-phone" role="img" aria-label="Order button" title="Order button"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-info" role="button" name="action_confirm" string="Receive" type="object" attrs="{'invisible': [('state','!=','ordered')]}" groups="lunch.group_lunch_manager">
|
||||
<a class="btn btn-sm btn-primary" role="button" name="action_send" string="Send" type="object" attrs="{'invisible': [('state', '!=', 'ordered')]}" groups="lunch.group_lunch_manager">
|
||||
<i class="fa fa-paper-plane" role="img" aria-label="Send button" title="Send button"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-info" role="button" name="action_confirm" string="Receive" type="object" attrs="{'invisible': [('state','!=','sent')]}" groups="lunch.group_lunch_manager">
|
||||
<i class="fa fa-check" role="img" aria-label="Receive button" title="Receive button"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-danger" role="button" name="action_cancel" string="Cancel" type="object" attrs="{'invisible': [('state','=','cancelled')]}" groups="lunch.group_lunch_manager">
|
||||
<a class="btn btn-sm btn-danger" role="button" name="action_cancel" string="Cancel" type="object" attrs="{'invisible': [('state','in', ['cancelled', 'confirmed'])]}" groups="lunch.group_lunch_manager">
|
||||
<i class="fa fa-times" role="img" aria-label="Cancel button" title="Cancel button"/>
|
||||
</a>
|
||||
<a class="btn btn-sm btn-info" role="button" name="action_notify" string="Send Notification" type="object" attrs="{'invisible': ['|', ('state', '!=', 'confirmed'), ('notified', '=', True)]}" groups="lunch.group_lunch_manager">
|
||||
@@ -193,14 +202,18 @@
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="quantity" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="category_id" invisible="1"/>
|
||||
<field name="available_toppings_1" invisible="1"/>
|
||||
<field name="available_toppings_2" invisible="1"/>
|
||||
<field name="available_toppings_3" invisible="1"/>
|
||||
<field name="supplier_id" invisible="1"/>
|
||||
<field name="order_deadline_passed" invisible="1"/>
|
||||
<field name="available_today" invisible="1"/>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-0 pr-5">
|
||||
<field name="image_1920" widget="image" class="o_lunch_image" options="{'image_preview': 'image_128'}"/>
|
||||
@@ -251,10 +264,18 @@
|
||||
<field name="note" nolabel="1" placeholder="Information, allergens, ..." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" attrs="{'invisible': [('order_deadline_passed', '=', False)]}">
|
||||
<div class="col">
|
||||
<div class="alert alert-warning" role="alert">
|
||||
The orders for this vendor have already been sent.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<button string="Save" special="save" data-hotkey="v" class="oe_highlight" invisible="not context.get('active_id', False)"/>
|
||||
<button string="Add To Cart" name="add_to_cart" type="object" class="oe_highlight" invisible="context.get('active_id', False)" data-hotkey="w"/>
|
||||
<button string="Add To Cart" name="add_to_cart" type="object" class="oe_highlight" invisible="context.get('active_id', False)" attrs="{'invisible': [('order_deadline_passed', '=', True)]}" data-hotkey="w"/>
|
||||
<button string="Discard" special="cancel" data-hotkey="z"/>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user