[MERGE] lunch: improve supplier management
Make the lunch alerts blocking if ordering a product from a supplier if not available at the order time Add mail templates to generate emails to suppliers. This merge is only a first step before the Big Lunch Refactoring that will change forever the way peoples are considering eating lunch.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
'name': 'Lunch',
|
||||
'sequence': 120,
|
||||
'version': '1.0',
|
||||
'depends': ['base', 'web', 'decimal_precision'],
|
||||
'depends': ['decimal_precision', 'mail'],
|
||||
'category': 'Human Resources',
|
||||
'summary': 'Handle lunch orders of your employees',
|
||||
'description': """
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="lunch_order_line_action_order" model="ir.actions.server">
|
||||
<field name="name">Lunch: Order meals</field>
|
||||
<field name="model_id" ref="model_lunch_order_line"/>
|
||||
@@ -7,7 +8,7 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
records.order()
|
||||
action = records.order()
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -26,5 +27,121 @@ if records:
|
||||
<field name="state">code</field>
|
||||
<field name="code">records.cancel()</field>
|
||||
</record>
|
||||
</data>
|
||||
<data noupdate="0">
|
||||
<record id="lunch_order_mail_supplier" model="mail.template">
|
||||
<field name="name">Lunch: Send by email</field>
|
||||
<field name="model_id" ref="lunch.model_lunch_order"/>
|
||||
<field name="email_from">${ctx['order']['supplier_email'] |safe}</field>
|
||||
<field name="partner_to">${ctx['order']['supplier_id']}</field>
|
||||
<field name="subject">Orders for ${ctx['order']['company_name']}</field>
|
||||
<field name="body_html" type="html">
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"><tr><td align="center">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
|
||||
<tbody>
|
||||
<!-- HEADER -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr><td valign="middle">
|
||||
<span style="font-size: 10px;">Lunch Order</span><br/>
|
||||
</td><td valign="middle" align="right">
|
||||
<img src="/logo.png?company=${user.company_id.id}" style="padding: 0px; margin: 0px; height: auto; width: 80px;" t-att-alt="'%s' % company.name"/>
|
||||
</td></tr>
|
||||
<tr><td colspan="2" style="text-align:center;">
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin:16px 0px 16px 0px;"/>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- CONTENT -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr>
|
||||
<td valign="top" style="font-size: 13px;">
|
||||
<div>
|
||||
% set lines = ctx['lines']
|
||||
% set order = ctx['order']
|
||||
% set supplier = user.env['res.partner'].browse(order['supplier_id'])
|
||||
% set currency = user.env['res.currency'].browse(order['currency_id'])
|
||||
<p>
|
||||
Dear ${order['supplier_name']},
|
||||
</p><p>
|
||||
Here is, today orders for ${order['company_name']}:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
% for line in lines:
|
||||
<li>
|
||||
<strong>
|
||||
${line['product']}
|
||||
(x${line['quantity']})
|
||||
</strong>
|
||||
% if line['note']:
|
||||
<em>(${line['note']})</em>
|
||||
% endif
|
||||
<div style="display: inline-block; float:right">
|
||||
${format_amount(line['price'], currency)}
|
||||
</div>
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
|
||||
<p>Amounting in <strong>${format_amount(order['amount_total'], currency)}</strong>.</p>
|
||||
<p>Do not hesitate to contact us if you have any question.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center;">
|
||||
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- FOOTER -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; font-size: 11px; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr><td valign="middle" align="left">
|
||||
${user.company_id.name}
|
||||
</td></tr>
|
||||
<tr><td valign="middle" align="left" style="opacity: 0.7;">
|
||||
${user.company_id.phone}
|
||||
% if user.company_id.phone and (user.company_id.email or user.company_id.website)
|
||||
|
|
||||
% endif
|
||||
% if user.company_id.email
|
||||
<a href="'mailto:%s' % ${user.company_id.email}" style="text-decoration:none; color: #454748;">${user.company_id.email}</a>
|
||||
% endif
|
||||
% if user.company_id.email and user.company_id.website
|
||||
|
|
||||
% endif
|
||||
% if user.company_id.website
|
||||
<a href="'%s' % ${user.company_id.website}" style="text-decoration:none; color: #454748;">
|
||||
${user.company_id.website}
|
||||
</a>
|
||||
% endif
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td></tr>
|
||||
<!-- POWERED BY -->
|
||||
<tr><td align="center" style="min-width: 590px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: #F1F1F1; color: #454748; padding: 8px; border-collapse:separate;">
|
||||
<tr><td style="text-align: center; font-size: 13px;">
|
||||
Powered by <a target="_blank" href="https://www.odoo.com" style="color: #875A7B;">Odoo</a>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
+163
-22
@@ -9,6 +9,7 @@ import datetime
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import AccessError, ValidationError
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.osv import expression
|
||||
|
||||
|
||||
class LunchOrder(models.Model):
|
||||
@@ -164,7 +165,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)
|
||||
product_id = fields.Many2one('lunch.product', 'Product', required=True)
|
||||
product_id = fields.Many2one('lunch.product', 'Product', required=True,
|
||||
domain=[('available', '=', 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)
|
||||
@@ -183,13 +185,104 @@ class LunchOrderLine(models.Model):
|
||||
cashmove = fields.One2many('lunch.cashmove', 'order_id', 'Cash Move')
|
||||
currency_id = fields.Many2one('res.currency', related='order_id.currency_id')
|
||||
|
||||
@api.one
|
||||
def _check_supplier_availibility(self):
|
||||
products = self.mapped('product_id')
|
||||
if not all(product.available for product in products):
|
||||
supplier_name = ", ".join(product.supplier.display_name for product in products if not product.available)
|
||||
raise ValidationError(_("Vendor(s) '%s' is not available today") % supplier_name)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
""" Override as an onchange would not apply if using the history buttons """
|
||||
res = super(LunchOrderLine, self).create(vals)
|
||||
res.with_context(lunch_date=res.order_id.date)._check_supplier_availibility()
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def write(self, vals):
|
||||
""" Override as an onchange would not apply if using the history buttons """
|
||||
res = super(LunchOrderLine, self).write(vals)
|
||||
if vals.get('product_id'):
|
||||
for line in self:
|
||||
line.with_context(lunch_date=line.order_id.date)._check_supplier_availibility()
|
||||
return res
|
||||
|
||||
def order(self):
|
||||
"""
|
||||
The order_line is ordered to the vendor but isn't received yet
|
||||
"""
|
||||
if self.user_has_groups("lunch.group_lunch_manager"):
|
||||
self.state = 'ordered'
|
||||
self.write({'state': 'ordered'})
|
||||
|
||||
order = {
|
||||
'supplier': False,
|
||||
'company': False,
|
||||
'currency': False,
|
||||
}
|
||||
group_lines = {}
|
||||
for line in self:
|
||||
if not line.supplier:
|
||||
# do not send emails for products with no suppliers
|
||||
continue
|
||||
|
||||
if order['supplier'] and line.supplier != order['supplier']:
|
||||
raise ValidationError(_("Validate order for one supplier at a time to send emails (mixed orders from %s and %s)") % (
|
||||
order['supplier'].display_name, line.supplier.display_name))
|
||||
order['supplier'] = line.supplier
|
||||
|
||||
if order['company'] and line.order_id.company_id != order['company']:
|
||||
raise ValidationError(_("Validate order for one company at a time to send emails (mixed orders from %s and %s)") % (
|
||||
order['company'].name, line.order_id.company_id.name))
|
||||
order['company'] = line.order_id.company_id
|
||||
|
||||
if order['currency'] and line.currency_id != order['currency']:
|
||||
raise ValidationError(_("Validate order for one currency at a time to send emails (mixed orders from %s and %s)") % (
|
||||
order['currency'].name, line.currency_id.name))
|
||||
order['currency'] = line.currency_id
|
||||
|
||||
# group the order by products and note
|
||||
key = (line.product_id, line.note)
|
||||
group_lines.setdefault(key, 0)
|
||||
group_lines[key] += 1
|
||||
|
||||
order['company_name'] = order['company'].name
|
||||
order['currency_id'] = order['currency'].id
|
||||
order['supplier_id'] = order['supplier'].id
|
||||
order['supplier_name'] = order['supplier'].name
|
||||
order['supplier_email'] = order['supplier'].email_formatted
|
||||
|
||||
lines = []
|
||||
# sort by product name, note
|
||||
for product, note in sorted(group_lines, key=lambda k: (k[0].name, bool(k[1]))):
|
||||
quantity = group_lines[(product, note)]
|
||||
lines.append({
|
||||
'product': product.name,
|
||||
'note': note or '',
|
||||
'quantity': quantity,
|
||||
'price': product.price * quantity,
|
||||
})
|
||||
|
||||
order['amount_total'] = sum(l['price'] for l in lines)
|
||||
|
||||
template = self.env.ref('lunch.lunch_order_mail_supplier', raise_if_not_found=False)
|
||||
ctx = dict(
|
||||
default_composition_mode='comment',
|
||||
default_model='lunch.order',
|
||||
default_use_template=bool(template),
|
||||
default_template_id=template.id,
|
||||
default_lang=order['supplier'].lang or self.env.user.lang,
|
||||
order=order,
|
||||
lines=lines,
|
||||
)
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'mail.compose.message',
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
else:
|
||||
raise AccessError(_("Only your lunch manager processes the orders."))
|
||||
|
||||
@@ -236,6 +329,41 @@ class LunchProduct(models.Model):
|
||||
price = fields.Float('Price', digits=dp.get_precision('Account'))
|
||||
supplier = fields.Many2one('res.partner', 'Vendor')
|
||||
active = fields.Boolean(default=True)
|
||||
available = fields.Boolean(compute='_get_available_product', search='_search_available_products')
|
||||
|
||||
@api.depends('supplier')
|
||||
def _get_available_product(self):
|
||||
for product in self:
|
||||
if not product.supplier:
|
||||
product.available = True
|
||||
else:
|
||||
alerts = self.env['lunch.alert'].search([
|
||||
('partner_id', '=', self.supplier.id)
|
||||
])
|
||||
if alerts and not any(alert.display for alert in alerts):
|
||||
# every alert is not available
|
||||
product.available = False
|
||||
else:
|
||||
# no alert for the supplier or at least one is not available
|
||||
product.available = True
|
||||
|
||||
def _search_available_products(self, operator, value):
|
||||
alerts = self.env['lunch.alert'].search([])
|
||||
supplier_w_alerts = alerts.mapped('partner_id')
|
||||
available_suppliers = alerts.filtered(lambda a: a.display).mapped('partner_id')
|
||||
available_products = self.search([
|
||||
'|',
|
||||
('supplier', 'not in', supplier_w_alerts.ids),
|
||||
('supplier', 'in', available_suppliers.ids)
|
||||
])
|
||||
|
||||
if (operator in expression.NEGATIVE_TERM_OPERATORS and value) or \
|
||||
(operator not in expression.NEGATIVE_TERM_OPERATORS and not value):
|
||||
# e.g. (available = False) or (available != True)
|
||||
return [('id', 'not in', available_products.ids)]
|
||||
else:
|
||||
# e.g. (available = True) or (available != False)
|
||||
return [('id', 'in', available_products.ids)]
|
||||
|
||||
|
||||
class LunchProductCategory(models.Model):
|
||||
@@ -270,6 +398,7 @@ class LunchAlert(models.Model):
|
||||
given day, weekly or daily. The alert is displayed from start to end hour. """
|
||||
_name = 'lunch.alert'
|
||||
_description = 'Lunch Alert'
|
||||
_rec_name = 'message'
|
||||
|
||||
display = fields.Boolean(compute='_compute_display_get')
|
||||
message = fields.Text('Message', required=True)
|
||||
@@ -277,6 +406,8 @@ class LunchAlert(models.Model):
|
||||
('week', 'Every Week'),
|
||||
('days', 'Every Day')],
|
||||
string='Recurrence', required=True, index=True, default='specific')
|
||||
partner_id = fields.Many2one('res.partner', string="Vendor",
|
||||
help="If specified, the selected vendor can be ordered only on selected days")
|
||||
specific_day = fields.Date('Day', default=fields.Date.context_today)
|
||||
monday = fields.Boolean('Monday')
|
||||
tuesday = fields.Boolean('Tuesday')
|
||||
@@ -293,7 +424,8 @@ class LunchAlert(models.Model):
|
||||
def name_get(self):
|
||||
return [(alert.id, '%s %s' % (_('Alert'), '#%d' % alert.id)) for alert in self]
|
||||
|
||||
@api.one
|
||||
@api.depends('alert_type', 'specific_day', 'monday', 'tuesday', 'thursday',
|
||||
'friday', 'saturday', 'sunday', 'start_hour', 'end_hour')
|
||||
def _compute_display_get(self):
|
||||
"""
|
||||
This method check if the alert can be displayed today
|
||||
@@ -302,7 +434,6 @@ class LunchAlert(models.Model):
|
||||
if alert type is day : True
|
||||
return : Message if can_display_alert is True else False
|
||||
"""
|
||||
|
||||
days_codes = {'0': 'sunday',
|
||||
'1': 'monday',
|
||||
'2': 'tuesday',
|
||||
@@ -310,22 +441,32 @@ class LunchAlert(models.Model):
|
||||
'4': 'thursday',
|
||||
'5': 'friday',
|
||||
'6': 'saturday'}
|
||||
can_display_alert = {
|
||||
'specific': (str(self.specific_day) == fields.Date.context_today(self)),
|
||||
'week': self[days_codes[datetime.datetime.now().strftime('%w')]],
|
||||
'days': True
|
||||
}
|
||||
fullday = False
|
||||
now = datetime.datetime.now()
|
||||
if self.env.context.get('lunch_date'):
|
||||
# lunch_date is a fields.Date -> 00:00:00
|
||||
lunch_date = fields.Datetime.from_string(self.env.context['lunch_date'])
|
||||
# if lunch_date is in the future, planned lunch, ignore hours
|
||||
fullday = lunch_date > now
|
||||
now = max(lunch_date, now)
|
||||
mynow = fields.Datetime.context_timestamp(self, now)
|
||||
|
||||
if can_display_alert[self.alert_type]:
|
||||
mynow = fields.Datetime.context_timestamp(self, datetime.datetime.now())
|
||||
hour_to = int(self.end_hour)
|
||||
min_to = int((self.end_hour - hour_to) * 60)
|
||||
to_alert = datetime.time(hour_to, min_to)
|
||||
hour_from = int(self.start_hour)
|
||||
min_from = int((self.start_hour - hour_from) * 60)
|
||||
from_alert = datetime.time(hour_from, min_from)
|
||||
for alert in self:
|
||||
can_display_alert = {
|
||||
'specific': (str(alert.specific_day) == fields.Date.to_string(mynow)),
|
||||
'week': alert[days_codes[mynow.strftime('%w')]],
|
||||
'days': True
|
||||
}
|
||||
|
||||
if from_alert <= mynow.time() <= to_alert:
|
||||
self.display = True
|
||||
else:
|
||||
self.display = False
|
||||
if can_display_alert[alert.alert_type]:
|
||||
hour_to = int(alert.end_hour)
|
||||
min_to = int((alert.end_hour - hour_to) * 60)
|
||||
to_alert = datetime.time(hour_to, min_to)
|
||||
hour_from = int(alert.start_hour)
|
||||
min_from = int((alert.start_hour - hour_from) * 60)
|
||||
from_alert = datetime.time(hour_from, min_from)
|
||||
|
||||
if fullday or (from_alert <= mynow.time() <= to_alert):
|
||||
alert.display = True
|
||||
else:
|
||||
alert.display = False
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import common
|
||||
|
||||
from datetime import date, datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
class Test_Lunch(common.TransactionCase):
|
||||
|
||||
@@ -11,18 +14,17 @@ class Test_Lunch(common.TransactionCase):
|
||||
super(Test_Lunch, self).setUp()
|
||||
|
||||
self.demo_user = self.env['res.users'].search([('name', '=', 'Marc Brown')])
|
||||
self.product_bolognese_ref = self.env['ir.model.data'].get_object_reference('lunch', 'product_Bolognese')
|
||||
self.product_Bolognese_id = self.product_bolognese_ref and self.product_bolognese_ref[1] or False
|
||||
self.product_Bolognese_id = self.env.ref('lunch.product_Bolognese')
|
||||
self.new_id_order = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'order_line_ids': '[]',
|
||||
})
|
||||
self.new_id_order_line = self.env['lunch.order.line'].create({
|
||||
'order_id': self.new_id_order.id,
|
||||
'product_id': self.product_Bolognese_id,
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
'note': '+Emmental',
|
||||
'cashmove': [],
|
||||
'price': self.env['lunch.product'].browse(self.product_Bolognese_id).price,
|
||||
'price': self.product_Bolognese_id.price,
|
||||
})
|
||||
|
||||
def test_00_lunch_order(self):
|
||||
@@ -60,3 +62,88 @@ class Test_Lunch(common.TransactionCase):
|
||||
#We check that the state is cancelled and that the cashmove has been deleted
|
||||
self.assertEqual(self.order_one.state, 'cancelled')
|
||||
self.assertFalse(self.order_one.cashmove)
|
||||
|
||||
def test_03_lunch_alert(self):
|
||||
""" specify a lunch alert and make sure it is not possible to make an
|
||||
order that day
|
||||
"""
|
||||
alert_01 = self.env['lunch.alert'].create({
|
||||
'message': 'Order Bolognese only on Tuesday',
|
||||
'partner_id': self.product_Bolognese_id.supplier.id,
|
||||
'alert_type': 'week',
|
||||
'tuesday': True
|
||||
})
|
||||
|
||||
patcher_date = patch('odoo.addons.lunch.models.lunch.datetime.date', wraps=date)
|
||||
patcher_datetime = patch('odoo.addons.lunch.models.lunch.datetime.datetime', wraps=datetime)
|
||||
mock_date = patcher_date.start()
|
||||
mock_datetime = patcher_datetime.start()
|
||||
|
||||
mock_date.today.return_value = date(2018, 8, 14) # a Tuesday
|
||||
mock_datetime.now.return_value = datetime(2018, 8, 14, 9, 0, 0)
|
||||
|
||||
# We check that we can make an order on a Tuesday
|
||||
order_01 = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'order_line_ids': [(0, 0, {
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
})]
|
||||
})
|
||||
order_01.order_line_ids.order()
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
# Planning an order to an non-authorized day must not be possible
|
||||
order_02 = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'date': "2018-08-15",
|
||||
'order_line_ids': [(0, 0, {
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
})]
|
||||
})
|
||||
|
||||
alert_02 = self.env['lunch.alert'].create({
|
||||
'message': 'Working one more day',
|
||||
'partner_id': self.product_Bolognese_id.supplier.id,
|
||||
'alert_type': 'specific',
|
||||
'specific_day': date(2018, 8, 15)
|
||||
})
|
||||
|
||||
# should now be possible to order tomorrow
|
||||
order_03 = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'date': "2018-08-15",
|
||||
'order_line_ids': [(0, 0, {
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
})]
|
||||
})
|
||||
|
||||
# should be possible to planned on an allowed day
|
||||
order_04 = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'date': "2018-08-21", # next Tuesday
|
||||
'order_line_ids': [(0, 0, {
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
})]
|
||||
})
|
||||
order_04.order_line_ids.order()
|
||||
|
||||
# combinaision of alerts should work
|
||||
alert_03 = self.env['lunch.alert'].create({
|
||||
'message': 'Order Bolognese also on Wednesday',
|
||||
'partner_id': self.product_Bolognese_id.supplier.id,
|
||||
'alert_type': 'week',
|
||||
'wednesday': True
|
||||
})
|
||||
# Planning an order Wednesday must now be possible
|
||||
order_05 = self.env['lunch.order'].create({
|
||||
'user_id': self.demo_user.id,
|
||||
'date': "2018-08-22", # next Wednesday
|
||||
'order_line_ids': [(0, 0, {
|
||||
'product_id': self.product_Bolognese_id.id,
|
||||
})]
|
||||
})
|
||||
order_05.order_line_ids.order()
|
||||
|
||||
|
||||
patcher_date.stop()
|
||||
patcher_datetime.stop()
|
||||
|
||||
@@ -477,7 +477,7 @@
|
||||
<separator string='Select your order'/>
|
||||
<field name='order_line_ids'>
|
||||
<tree string='List' editable='bottom'>
|
||||
<field name='product_id'/>
|
||||
<field name='product_id' context="{'lunch_date': parent.date}"/>
|
||||
<field name='note' />
|
||||
<field name='price'/>
|
||||
<field name='supplier' invisible="1"/>
|
||||
@@ -485,7 +485,7 @@
|
||||
</tree>
|
||||
<form string='Lunch Order Form'>
|
||||
<group>
|
||||
<field name='product_id'/>
|
||||
<field name='product_id' context="{'lunch_date': parent.date}"/>
|
||||
<field name='note' />
|
||||
<field name='price'/>
|
||||
</group>
|
||||
@@ -660,37 +660,52 @@
|
||||
<field name="model">lunch.alert</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object"
|
||||
class="oe_stat_button" icon="fa-archive">
|
||||
<field name="active" widget="boolean_button"
|
||||
options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
</div>
|
||||
<group>
|
||||
<group string="Schedule Date">
|
||||
<field name="alert_type"/>
|
||||
<field name="specific_day" attrs="{'invisible': [('alert_type','!=','specific')], 'required':[('alert_type','=','specific')]}"/>
|
||||
</group>
|
||||
<group string="Schedule Hour">
|
||||
<field name='start_hour' widget='float_time'/>
|
||||
<field name='end_hour' widget='float_time'/>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('alert_type','!=','week')]}">
|
||||
<group col="4">
|
||||
<field name="monday"/>
|
||||
<field name="tuesday"/>
|
||||
<field name="wednesday"/>
|
||||
<field name="thursday"/>
|
||||
<field name="friday"/>
|
||||
<field name="saturday"/>
|
||||
<field name="sunday"/>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object"
|
||||
class="oe_stat_button" icon="fa-archive">
|
||||
<field name="active" widget="boolean_button"
|
||||
options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
</div>
|
||||
<group>
|
||||
<group string="Schedule">
|
||||
<group colspan="4">
|
||||
<field name="alert_type"/>
|
||||
<field name="specific_day"
|
||||
attrs="{'invisible': [('alert_type','!=','specific')], 'required':[('alert_type','=','specific')]}"/>
|
||||
<field name='start_hour' widget='float_time' />
|
||||
<field name='end_hour' widget='float_time' />
|
||||
</group>
|
||||
<group col="4" attrs="{'invisible': [('alert_type','!=','week')]}">
|
||||
<field name="monday"/>
|
||||
<field name="tuesday"/>
|
||||
<field name="wednesday"/>
|
||||
<field name="thursday"/>
|
||||
<field name="friday"/>
|
||||
<field name="saturday"/>
|
||||
<field name="sunday"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Vendor">
|
||||
<group colspan="4">
|
||||
<field name="partner_id"/>
|
||||
<field name="display" invisible="True"/>
|
||||
</group>
|
||||
<div class="oe_grey" colspan="4"
|
||||
attrs="{'invisible': ['|', ('partner_id', '=', False), ('display', '=', True)]}">
|
||||
Products from this vendor can <strong>not</strong> be order at the moment.
|
||||
</div>
|
||||
<div class="oe_grey" colspan="4"
|
||||
attrs="{'invisible': ['|', ('partner_id', '=', False), ('display', '=', False)]}">
|
||||
Products from this vendor can be order at the moment.
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group string='Message'>
|
||||
<field name='message' nolabel='1' placeholder="Write the message you want to display during the defined period..."/>
|
||||
</group>
|
||||
<group string='Message'>
|
||||
<field name='message' nolabel='1' placeholder="Write the message you want to display during the defined period..."/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user