[MIGR] lunch: migration to the new API, cleaning and new
widget for displaying previous orders. Detailed changes : - previous order is not a computed field, with its own custom widget that has been designed according the new spec for widgets; - useless wizards have been removed, and replaced by some server actions that perform the same action with less code and views; - removed deprecated or incomplete reporting; - some renaming to follow the new specifications of module coding
This commit is contained in:
committed by
Thibault Delavallée
parent
058d403309
commit
3d63c15a56
@@ -1,8 +1,8 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 Tiny SPRL (<http://tiny.be>).
|
||||
# Odoo, Open Source Management Solution
|
||||
# Copyright (C) 2004-Today Odoo SA (<https://www.odoo.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -15,10 +15,8 @@
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import models
|
||||
import report
|
||||
import wizard
|
||||
|
||||
+13
-15
@@ -1,21 +1,21 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
{
|
||||
'author': 'Odoo SA',
|
||||
'name': 'Lunch',
|
||||
'author': 'OpenERP SA',
|
||||
'version': '0.2',
|
||||
'depends': ['base', 'report'],
|
||||
'version': '1.0',
|
||||
'depends': ['base', 'web', 'decimal_precision'],
|
||||
'category': 'Tools',
|
||||
'summary': 'Lunch Order, Meal, Food',
|
||||
'description': """
|
||||
The base module to manage lunch.
|
||||
================================
|
||||
|
||||
Many companies order sandwiches, pizzas and other, from usual suppliers, for their employees to offer them more facilities.
|
||||
Many companies order sandwiches, pizzas and other, from usual suppliers, for their employees to offer them more facilities.
|
||||
|
||||
However lunches management within the company requires proper administration especially when the number of employees or suppliers is important.
|
||||
However lunches management within the company requires proper administration especially when the number of employees or suppliers is important.
|
||||
|
||||
The “Lunch Order” module has been developed to make this management easier but also to offer employees more tools and usability.
|
||||
The “Lunch Order” module has been developed to make this management easier but also to offer employees more tools and usability.
|
||||
|
||||
In addition to a full meal and supplier management, this module offers the possibility to display warning and provides quick order selection based on employee’s preferences.
|
||||
|
||||
@@ -23,17 +23,15 @@ If you want to save your employees' time and avoid them to always have coins in
|
||||
""",
|
||||
'data': [
|
||||
'security/lunch_security.xml',
|
||||
'views/lunch_views.xml',
|
||||
'views/lunch_templates.xml',
|
||||
'wizard/lunch_order_view.xml',
|
||||
'wizard/lunch_validation_view.xml',
|
||||
'wizard/lunch_cancel_view.xml',
|
||||
'report/lunch_report_views.xml',
|
||||
'report/report_lunch_order_view.xml',
|
||||
'report/lunch_order_templates.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'report/lunch_order_views.xml',
|
||||
'report/lunch_order_templates.xml',
|
||||
'views/lunch_templates.xml',
|
||||
'views/lunch_views.xml',
|
||||
'data/lunch_data.xml',
|
||||
],
|
||||
'demo': ['data/lunch_demo.xml'],
|
||||
'qweb': ['static/src/xml/lunch.xml', ],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'certificate': '001292377792581874189',
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="lunch_order_line_action_order" model="ir.actions.server">
|
||||
<field name="name">Order meals</field>
|
||||
<field name="model_id" ref="model_lunch_order_line"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if context.get('active_ids'):
|
||||
self.order(cr, uid, context['active_ids'], context=context)
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_lunch_order_line_action_order" model="ir.values">
|
||||
<field name="model_id" ref="model_lunch_order_line" />
|
||||
<field name="name">Order meals</field>
|
||||
<field name="key2">client_action_multi</field>
|
||||
<field eval="'ir.actions.server,%d'%lunch_order_line_action_order" name="value"/>
|
||||
<field name="key">action</field>
|
||||
<field name="model">lunch.order.line</field>
|
||||
</record>
|
||||
|
||||
<record id="lunch_order_line_action_confirm" model="ir.actions.server">
|
||||
<field name="name">Receive meals</field>
|
||||
<field name="model_id" ref="model_lunch_order_line"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if context.get('active_ids'):
|
||||
self.confirm(cr, uid, context['active_ids'], context=context)
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_lunch_order_line_action_confirm" model="ir.values">
|
||||
<field name="model_id" ref="model_lunch_order_line" />
|
||||
<field name="name">Receive meals</field>
|
||||
<field name="key2">client_action_multi</field>
|
||||
<field eval="'ir.actions.server,%d'%lunch_order_line_action_confirm" name="value"/>
|
||||
<field name="key">action</field>
|
||||
<field name="model">lunch.order.line</field>
|
||||
</record>
|
||||
|
||||
<record id="lunch_order_line_action_cancel" model="ir.actions.server">
|
||||
<field name="name">Cancel meals</field>
|
||||
<field name="model_id" ref="model_lunch_order_line"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if context.get('active_ids'):
|
||||
self.cancel(cr, uid, context['active_ids'], context=context)
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_lunch_order_line_action_cancel" model="ir.values">
|
||||
<field name="model_id" ref="model_lunch_order_line" />
|
||||
<field name="name">Cancel meals</field>
|
||||
<field name="key2">client_action_multi</field>
|
||||
<field eval="'ir.actions.server,%d'%lunch_order_line_action_cancel" name="value"/>
|
||||
<field name="key">action</field>
|
||||
<field name="model">lunch.order.line</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('lunch.group_lunch_user'))]"/>
|
||||
<field name="groups_id" eval="[(4, ref('lunch.group_lunch_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="lunch.product.category" id="categ_sandwich">
|
||||
@@ -109,29 +109,30 @@
|
||||
|
||||
<record model="lunch.order" id="order_1">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-23')"/>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d')"/>
|
||||
<field name="order_line_ids" eval="[]"/>
|
||||
<field name="state">new</field>
|
||||
</record>
|
||||
|
||||
<record model="lunch.order" id="order_2">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-22')"/>
|
||||
<field name="date" eval="DateTime.now().strftime('%Y-%m-%d')"/>
|
||||
<field name="order_line_ids" eval="[]"/>
|
||||
<field name="state">confirmed</field>
|
||||
</record>
|
||||
|
||||
<record model="lunch.order" id="order_3">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-24')"/>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=2)).strftime('%Y-%m-%d')"/>
|
||||
<field name="order_line_ids" eval="[]"/>
|
||||
<field name="state">partially</field>
|
||||
<field name="state">confirmed</field>
|
||||
</record>
|
||||
|
||||
<record model="lunch.order.line" id="order_line_1">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="product_id" ref="product_Bolognese"/>
|
||||
<field name="date" eval="time.strftime('2012-10-23')"/>
|
||||
<field name="price">7.70</field>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">new</field>
|
||||
<field name="supplier" ref="partner_pizza_inn"/>
|
||||
<field name="note">+Emmental</field>
|
||||
@@ -141,7 +142,8 @@
|
||||
<record model="lunch.order.line" id="order_line_2">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="product_id" ref="product_italiana"/>
|
||||
<field name="date" eval="time.strftime('2012-10-22')"/>
|
||||
<field name="price">7.40</field>
|
||||
<field name="date" eval="DateTime.now().strftime('%Y-%m-%d')"/>
|
||||
<field name="state">confirmed</field>
|
||||
<field name="supplier" ref="partner_pizza_inn"/>
|
||||
<field name="note">+Mushrooms</field>
|
||||
@@ -151,7 +153,8 @@
|
||||
<record model="lunch.order.line" id="order_line_3">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="product_id" ref="product_gouda"/>
|
||||
<field name="date" eval="time.strftime('2012-10-24')"/>
|
||||
<field name="price">2.50</field>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=2)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">cancelled</field>
|
||||
<field name="supplier" ref="partner_coin_gourmand"/>
|
||||
<field name="note">+Salad +Tomatoes +Cucumbers</field>
|
||||
@@ -161,16 +164,17 @@
|
||||
<record model="lunch.order.line" id="order_line_4">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="product_id" ref="product_chicken_curry"/>
|
||||
<field name="date" eval="time.strftime('2012-10-24')"/>
|
||||
<field name="price">2.60</field>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=2)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">confirmed</field>
|
||||
<field name="supplier" ref="partner_coin_gourmand"/>
|
||||
<field name="note">+Salad +Tomatoes +Eggs</field>
|
||||
<field name="order_id" ref="order_3"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="lunch.cashmove" id="cashmove_1">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-23')"/>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d')"/>
|
||||
<field name="description">Pizza Italiana</field>
|
||||
<field name="amount">-7.40</field>
|
||||
<field name="order_id" ref="order_2"/>
|
||||
@@ -179,7 +183,7 @@
|
||||
|
||||
<record model="lunch.cashmove" id="cashmove_2">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-24')"/>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=2)).strftime('%Y-%m-%d')"/>
|
||||
<field name="description">Chicken curry</field>
|
||||
<field name="amount">-2.60</field>
|
||||
<field name="order_id" ref="order_3"/>
|
||||
@@ -188,15 +192,24 @@
|
||||
|
||||
<record model="lunch.cashmove" id="cashmove_3">
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="date" eval="time.strftime('2012-10-24')"/>
|
||||
<field name="date" eval="(DateTime.now() + timedelta(days=2)).strftime('%Y-%m-%d')"/>
|
||||
<field name="description">Payment: 5 lunch tickets (6€)</field>
|
||||
<field name="amount">30</field>
|
||||
<field name="state">payment</field>
|
||||
</record>
|
||||
|
||||
<record model="lunch.alert" id="alert_1">
|
||||
<field name="message">Lunch must be ordered before 10h30 am</field>
|
||||
<field name="alert_type">week</field>
|
||||
<field name="monday" eval="True"/>
|
||||
<field name="tuesday" eval="True"/>
|
||||
<field name="wednesday" eval="True"/>
|
||||
<field name="thursday" eval="True"/>
|
||||
<field name="friday" eval="True"/>
|
||||
<field name="saturday" eval="False"/>
|
||||
<field name="sunday" eval="False"/>
|
||||
<field name="start_hour">7</field>
|
||||
<field name="end_hour">23</field>
|
||||
<field name="message">Lunch must be ordered before 10:30 AM</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import lunch
|
||||
|
||||
+232
-455
@@ -1,501 +1,278 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from xml.sax.saxutils import escape
|
||||
import time
|
||||
from openerp.osv import fields, osv
|
||||
from datetime import datetime
|
||||
from lxml import etree
|
||||
from openerp import tools
|
||||
from openerp.tools.translate import _
|
||||
import datetime
|
||||
|
||||
class lunch_order(osv.Model):
|
||||
"""
|
||||
lunch order (contains one or more lunch order line(s))
|
||||
from openerp import models, fields, api, _
|
||||
import openerp.addons.decimal_precision as dp
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class LunchOrder(models.Model):
|
||||
"""
|
||||
A lunch order contains one or more lunch order line(s). It is associated to a user for a given
|
||||
date. When creating a lunch order, applicable lunch alerts are displayed.
|
||||
"""
|
||||
_name = 'lunch.order'
|
||||
_description = 'Lunch Order'
|
||||
_order = 'date desc'
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
if not ids:
|
||||
return []
|
||||
res = []
|
||||
for elmt in self.browse(cr, uid, ids, context=context):
|
||||
name = _("Lunch Order")
|
||||
name = name + ' ' + str(elmt.id)
|
||||
res.append((elmt.id, name))
|
||||
return res
|
||||
|
||||
def _price_get(self, cr, uid, ids, name, arg, context=None):
|
||||
"""
|
||||
user_id = fields.Many2one('res.users', 'User', required=True, readonly=True,
|
||||
states={'new': [('readonly', False)]},
|
||||
default=lambda self: self.env.uid)
|
||||
date = fields.Date('Date', required=True, readonly=True,
|
||||
states={'new': [('readonly', False)]},
|
||||
default=fields.Date.context_today)
|
||||
order_line_ids = fields.One2many('lunch.order.line', 'order_id', 'Products',
|
||||
ondelete="cascade", readonly=True, copy=True,
|
||||
states={'new': [('readonly', False)], False: [('readonly', False)]})
|
||||
total = fields.Float(compute='_compute_total', string="Total", store=True)
|
||||
state = fields.Selection([('new', 'New'),
|
||||
('confirmed', 'Received'),
|
||||
('cancelled', 'Cancelled')],
|
||||
'Status', readonly=True, index=True, copy=False, default='new',
|
||||
compute='_compute_order_state')
|
||||
alerts = fields.Text(compute='_compute_alerts_get', string="Alerts")
|
||||
previous_order_ids = fields.One2many(comodel_name='lunch.order.line',
|
||||
compute='_compute_get_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)
|
||||
|
||||
@api.one
|
||||
@api.depends('order_line_ids')
|
||||
def _compute_total(self):
|
||||
"""
|
||||
get and sum the order lines' price
|
||||
"""
|
||||
result = dict.fromkeys(ids, 0)
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
result[order.id] = sum(order_line.product_id.price
|
||||
for order_line in order.order_line_ids)
|
||||
return result
|
||||
self.total = sum(
|
||||
orderline.price for orderline in self.order_line_ids)
|
||||
|
||||
def _fetch_orders_from_lines(self, cr, uid, ids, name, context=None):
|
||||
"""
|
||||
return the list of lunch orders to which belong the order lines `ids´
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
return [(order.id, '%s %s' % (_('Lunch Order'), '#%d' % order.id)) for order in self]
|
||||
|
||||
@api.depends('state')
|
||||
def _compute_alerts_get(self):
|
||||
"""
|
||||
result = set()
|
||||
for order_line in self.browse(cr, uid, ids, context=context):
|
||||
if order_line.order_id:
|
||||
result.add(order_line.order_id.id)
|
||||
return list(result)
|
||||
|
||||
def add_preference(self, cr, uid, ids, pref_id, context=None):
|
||||
"""
|
||||
create a new order line based on the preference selected (pref_id)
|
||||
"""
|
||||
assert len(ids) == 1
|
||||
orderline_ref = self.pool.get('lunch.order.line')
|
||||
prod_ref = self.pool.get('lunch.product')
|
||||
order = self.browse(cr, uid, ids[0], context=context)
|
||||
pref = orderline_ref.browse(cr, uid, pref_id, context=context)
|
||||
new_order_line = {
|
||||
'date': order.date,
|
||||
'user_id': uid,
|
||||
'product_id': pref.product_id.id,
|
||||
'note': pref.note,
|
||||
'order_id': order.id,
|
||||
'price': pref.product_id.price,
|
||||
'supplier': pref.product_id.supplier.id
|
||||
}
|
||||
return orderline_ref.create(cr, uid, new_order_line, context=context)
|
||||
|
||||
def _alerts_get(self, cr, uid, ids, name, arg, context=None):
|
||||
"""
|
||||
get the alerts to display on the order form
|
||||
"""
|
||||
result = {}
|
||||
alert_msg = self._default_alerts_get(cr, uid, context=context)
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if order.state == 'new':
|
||||
result[order.id] = alert_msg
|
||||
return result
|
||||
|
||||
def check_day(self, alert):
|
||||
"""
|
||||
This method is used by can_display_alert
|
||||
to check if the alert day corresponds
|
||||
to the current day
|
||||
"""
|
||||
today = datetime.now().isoweekday()
|
||||
assert 1 <= today <= 7, "Should be between 1 and 7"
|
||||
mapping = dict((idx, name) for idx, name in enumerate('days monday tuesday wednesday thursday friday saturday sunday'.split()))
|
||||
return alert[mapping[today]]
|
||||
|
||||
def can_display_alert(self, alert):
|
||||
"""
|
||||
This method check if the alert can be displayed today
|
||||
"""
|
||||
if alert.alter_type == 'specific':
|
||||
#the alert is only activated on a specific day
|
||||
return alert.specific_day == time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
|
||||
elif alert.alter_type == 'week':
|
||||
#the alert is activated during some days of the week
|
||||
return self.check_day(alert)
|
||||
return True # alter_type == 'days' (every day)
|
||||
|
||||
def _default_alerts_get(self, cr, uid, context=None):
|
||||
"""
|
||||
get the alerts to display on the order form
|
||||
"""
|
||||
alert_ref = self.pool.get('lunch.alert')
|
||||
alert_ids = alert_ref.search(cr, uid, [], context=context)
|
||||
alert_msg = []
|
||||
for alert in alert_ref.browse(cr, uid, alert_ids, context=context):
|
||||
#check if the address must be displayed today
|
||||
if self.can_display_alert(alert):
|
||||
#display the address only during its active time
|
||||
mynow = fields.datetime.context_timestamp(cr, uid, datetime.now(), context=context)
|
||||
hour_to = int(alert.active_to)
|
||||
min_to = int((alert.active_to - hour_to) * 60)
|
||||
to_alert = datetime.strptime(str(hour_to) + ":" + str(min_to), "%H:%M")
|
||||
hour_from = int(alert.active_from)
|
||||
min_from = int((alert.active_from - hour_from) * 60)
|
||||
from_alert = datetime.strptime(str(hour_from) + ":" + str(min_from), "%H:%M")
|
||||
if mynow.time() >= from_alert.time() and mynow.time() <= to_alert.time():
|
||||
alert_msg.append(alert.message)
|
||||
return '\n'.join(alert_msg)
|
||||
alert_msg = [alert.message
|
||||
for alert in self.env['lunch.alert'].search([])
|
||||
if alert.display]
|
||||
|
||||
def onchange_price(self, cr, uid, ids, order_line_ids, context=None):
|
||||
if self.state == 'new':
|
||||
self.alerts = '\n'.join(alert_msg)
|
||||
|
||||
@api.depends('state')
|
||||
def _compute_get_previous_order_ids(self):
|
||||
prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid)], limit=20, order='id desc')
|
||||
# If we return return 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()
|
||||
|
||||
@api.onchange('total')
|
||||
def _onchange_total(self):
|
||||
"""
|
||||
Onchange methode that refresh the total price of order
|
||||
Calculates the forecasted balance of the user, taking into account the current order
|
||||
"""
|
||||
res = {'value': {'total': 0.0}}
|
||||
order_line_ids = self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context=context)
|
||||
if order_line_ids:
|
||||
tot = 0.0
|
||||
product_ref = self.pool.get("lunch.product")
|
||||
for prod in order_line_ids:
|
||||
if 'product_id' in prod:
|
||||
tot += product_ref.browse(cr, uid, prod['product_id'], context=context).price
|
||||
prev_cashmove = self.env['lunch.cashmove'].search([('user_id', '=', self.user_id.id)])
|
||||
balance = sum(cashmove.amount for cashmove in prev_cashmove)
|
||||
|
||||
if self.total > balance:
|
||||
raise UserError('%s (%s %s)' % (_('Insufficient balance. The total amount of the order is larger than the available balance'), balance, self.currency_id.name))
|
||||
|
||||
@api.one
|
||||
@api.constrains('date')
|
||||
def _check_date(self):
|
||||
"""
|
||||
Prevents the user to create an order in the past
|
||||
"""
|
||||
date_order = datetime.datetime.strptime(self.date, '%Y-%m-%d')
|
||||
date_today = datetime.datetime.strptime(fields.Date.context_today(self), '%Y-%m-%d')
|
||||
if (date_order < date_today):
|
||||
raise UserError(_('The date of your order is in the past.'))
|
||||
|
||||
@api.one
|
||||
@api.depends('order_line_ids.state')
|
||||
def _compute_order_state(self):
|
||||
"""
|
||||
Update the state of lunch.order based on its orderlines. Here is the logic:
|
||||
- if at least one order line is cancelled, the order is set as cancelled
|
||||
- if no line is cancelled but at least one line is not confirmed, the order is set as new
|
||||
- if all lines are confirmed, the order is set as confirmed
|
||||
"""
|
||||
if not self.order_line_ids:
|
||||
self.state = 'new'
|
||||
else:
|
||||
isConfirmed = True
|
||||
for orderline in self.order_line_ids:
|
||||
if orderline.state == 'cancelled':
|
||||
self.state = 'cancelled'
|
||||
return
|
||||
elif orderline.state == 'confirmed':
|
||||
continue
|
||||
else:
|
||||
tot += prod['price']
|
||||
res = {'value': {'total': tot}}
|
||||
return res
|
||||
isConfirmed = False
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""
|
||||
this method catch unexisting method call and if it starts with
|
||||
add_preference_'n' we execute the add_preference method with
|
||||
'n' as parameter
|
||||
"""
|
||||
if attr.startswith('add_preference_'):
|
||||
pref_id = int(attr[15:])
|
||||
def specific_function(cr, uid, ids, context=None):
|
||||
return self.add_preference(cr, uid, ids, pref_id, context=context)
|
||||
return specific_function
|
||||
return super(lunch_order, self).__getattr__(attr)
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
|
||||
"""
|
||||
Add preferences in the form view of order.line
|
||||
"""
|
||||
res = super(lunch_order,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
|
||||
line_ref = self.pool.get("lunch.order.line")
|
||||
if view_type == 'form':
|
||||
doc = etree.XML(res['arch'])
|
||||
pref_ids = line_ref.search(cr, uid, [('user_id', '=', uid)], order='id desc', context=context)
|
||||
xml_start = etree.Element("div")
|
||||
#If there are no preference (it's the first time for the user)
|
||||
if len(pref_ids)==0:
|
||||
#create Elements
|
||||
xml_no_pref_1 = etree.Element("div")
|
||||
xml_no_pref_1.set('class','oe_inline oe_lunch_intro')
|
||||
xml_no_pref_2 = etree.Element("h3")
|
||||
xml_no_pref_2.text = _("This is the first time you order a meal")
|
||||
xml_no_pref_3 = etree.Element("p")
|
||||
xml_no_pref_3.set('class','oe_grey')
|
||||
xml_no_pref_3.text = _("Select a product and put your order comments on the note.")
|
||||
xml_no_pref_4 = etree.Element("p")
|
||||
xml_no_pref_4.set('class','oe_grey')
|
||||
xml_no_pref_4.text = _("Your favorite meals will be created based on your last orders.")
|
||||
xml_no_pref_5 = etree.Element("p")
|
||||
xml_no_pref_5.set('class','oe_grey')
|
||||
xml_no_pref_5.text = _("Don't forget the alerts displayed in the reddish area")
|
||||
#structure Elements
|
||||
xml_start.append(xml_no_pref_1)
|
||||
xml_no_pref_1.append(xml_no_pref_2)
|
||||
xml_no_pref_1.append(xml_no_pref_3)
|
||||
xml_no_pref_1.append(xml_no_pref_4)
|
||||
xml_no_pref_1.append(xml_no_pref_5)
|
||||
#Else: the user already have preferences so we display them
|
||||
if isConfirmed:
|
||||
self.state = 'confirmed'
|
||||
else:
|
||||
preferences = line_ref.browse(cr, uid, pref_ids, context=context)
|
||||
categories = {} #store the different categories of products in preference
|
||||
count = 0
|
||||
for pref in preferences:
|
||||
#For each preference
|
||||
categories.setdefault(pref.product_id.category_id.name, {})
|
||||
#if this product has already been added to the categories dictionnary
|
||||
if pref.product_id.id in categories[pref.product_id.category_id.name]:
|
||||
#we check if for the same product the note has already been added
|
||||
if pref.note not in categories[pref.product_id.category_id.name][pref.product_id.id]:
|
||||
#if it's not the case then we add this to preferences
|
||||
categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref
|
||||
#if this product is not in the dictionnay, we add it
|
||||
else:
|
||||
categories[pref.product_id.category_id.name][pref.product_id.id] = {}
|
||||
categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref
|
||||
|
||||
currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
|
||||
|
||||
#For each preferences that we get, we will create the XML structure
|
||||
for key, value in categories.items():
|
||||
xml_pref_1 = etree.Element("div")
|
||||
xml_pref_1.set('class', 'oe_lunch_30pc')
|
||||
xml_pref_2 = etree.Element("h2")
|
||||
xml_pref_2.text = key
|
||||
xml_pref_1.append(xml_pref_2)
|
||||
i = 0
|
||||
value = value.values()
|
||||
#TODO: sorted_values is used for a quick and dirty hack in order to display the 5 last orders of each categories.
|
||||
#It would be better to fetch only the 5 items to display instead of fetching everything then sorting them in order to keep only the 5 last.
|
||||
#NB: The note could also be ignored + we could fetch the preferences on the most ordered products instead of the last ones...
|
||||
sorted_values = {}
|
||||
for val in value:
|
||||
for elmt in val.values():
|
||||
sorted_values[elmt.id] = elmt
|
||||
for key, pref in sorted(sorted_values.iteritems(), key=lambda (k, v): (k, v), reverse=True):
|
||||
#We only show 5 preferences per category (or it will be too long)
|
||||
if i == 5:
|
||||
break
|
||||
i += 1
|
||||
xml_pref_3 = etree.Element("div")
|
||||
xml_pref_3.set('class','oe_lunch_vignette')
|
||||
xml_pref_1.append(xml_pref_3)
|
||||
|
||||
xml_pref_4 = etree.Element("span")
|
||||
xml_pref_4.set('class','oe_lunch_button')
|
||||
xml_pref_3.append(xml_pref_4)
|
||||
|
||||
xml_pref_5 = etree.Element("button")
|
||||
xml_pref_5.set('name',"add_preference_"+str(pref.id))
|
||||
xml_pref_5.set('class','oe_link oe_i oe_button_plus')
|
||||
xml_pref_5.set('type','object')
|
||||
xml_pref_5.set('string','+')
|
||||
xml_pref_4.append(xml_pref_5)
|
||||
|
||||
xml_pref_6 = etree.Element("button")
|
||||
xml_pref_6.set('name',"add_preference_"+str(pref.id))
|
||||
xml_pref_6.set('class','oe_link oe_button_add')
|
||||
xml_pref_6.set('type','object')
|
||||
xml_pref_6.set('string',_("Add"))
|
||||
xml_pref_4.append(xml_pref_6)
|
||||
|
||||
xml_pref_7 = etree.Element("div")
|
||||
xml_pref_7.set('class','oe_group_text_button')
|
||||
xml_pref_3.append(xml_pref_7)
|
||||
|
||||
xml_pref_8 = etree.Element("div")
|
||||
xml_pref_8.set('class','oe_lunch_text')
|
||||
xml_pref_8.text = escape(pref.product_id.name)+str(" ")
|
||||
xml_pref_7.append(xml_pref_8)
|
||||
|
||||
price = pref.product_id.price or 0.0
|
||||
cur = currency.name or ''
|
||||
xml_pref_9 = etree.Element("span")
|
||||
xml_pref_9.set('class','oe_tag')
|
||||
xml_pref_9.text = str(price)+str(" ")+cur
|
||||
xml_pref_8.append(xml_pref_9)
|
||||
|
||||
xml_pref_10 = etree.Element("div")
|
||||
xml_pref_10.set('class','oe_grey')
|
||||
xml_pref_10.text = escape(pref.note or '')
|
||||
xml_pref_3.append(xml_pref_10)
|
||||
|
||||
xml_start.append(xml_pref_1)
|
||||
|
||||
first_node = doc.xpath("//div[@name='preferences']")
|
||||
if first_node and len(first_node)>0:
|
||||
first_node[0].append(xml_start)
|
||||
res['arch'] = etree.tostring(doc)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users', 'User Name', required=True, readonly=True, states={'new':[('readonly', False)]}),
|
||||
'date': fields.date('Date', required=True, readonly=True, states={'new':[('readonly', False)]}),
|
||||
'order_line_ids': fields.one2many('lunch.order.line', 'order_id', 'Products',
|
||||
ondelete="cascade", readonly=True, states={'new':[('readonly', False)]},
|
||||
copy=True),
|
||||
'total': fields.function(_price_get, string="Total", store={
|
||||
'lunch.order.line': (_fetch_orders_from_lines, ['product_id','order_id'], 20),
|
||||
}),
|
||||
'state': fields.selection([('new', 'New'), \
|
||||
('confirmed','Confirmed'), \
|
||||
('cancelled','Cancelled'), \
|
||||
('partially','Partially Confirmed')] \
|
||||
,'Status', readonly=True, select=True, copy=False),
|
||||
'alerts': fields.function(_alerts_get, string="Alerts", type='text'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
'date': fields.date.context_today,
|
||||
'state': 'new',
|
||||
'alerts': _default_alerts_get,
|
||||
}
|
||||
self.state = 'new'
|
||||
return
|
||||
|
||||
|
||||
class lunch_order_line(osv.Model):
|
||||
"""
|
||||
lunch order line: one lunch order can have many order lines
|
||||
"""
|
||||
class LunchOrderLine(models.Model):
|
||||
_name = 'lunch.order.line'
|
||||
_description = 'lunch order line'
|
||||
|
||||
def onchange_price(self, cr, uid, ids, product_id, context=None):
|
||||
if product_id:
|
||||
price = self.pool.get('lunch.product').browse(cr, uid, product_id, context=context).price
|
||||
return {'value': {'price': price}}
|
||||
return {'value': {'price': 0.0}}
|
||||
name = fields.Char(related='product_id.name', readonly=True)
|
||||
order_id = fields.Many2one('lunch.order', 'Order', ondelete='cascade', required=True)
|
||||
product_id = fields.Many2one('lunch.product', 'Product', 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)
|
||||
supplier = fields.Many2one('res.partner', string='Supplier', related='product_id.supplier',
|
||||
readonly=True, store=True)
|
||||
user_id = fields.Many2one('res.users', string='User', related='order_id.user_id',
|
||||
readonly=True, store=True)
|
||||
note = fields.Text('Note')
|
||||
price = fields.Float(related='product_id.price', readonly=True, store=True,
|
||||
digits_compute=dp.get_precision('Account'))
|
||||
state = fields.Selection([('new', 'New'),
|
||||
('confirmed', 'Received'),
|
||||
('ordered', 'Ordered'),
|
||||
('cancelled', 'Cancelled')],
|
||||
'Status', readonly=True, select=True, default='new')
|
||||
cashmove = fields.One2many('lunch.cashmove', 'order_id', 'Cash Move')
|
||||
currency_id = fields.Many2one('res.currency', related='order_id.currency_id')
|
||||
|
||||
def order(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
@api.one
|
||||
def order(self):
|
||||
"""
|
||||
The order_line is ordered to the supplier but isn't received yet
|
||||
"""
|
||||
self.write(cr, uid, ids, {'state': 'ordered'}, context=context)
|
||||
return self._update_order_lines(cr, uid, ids, context=context)
|
||||
self.state = 'ordered'
|
||||
|
||||
def confirm(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
confirm one or more order line, update order status and create new cashmove
|
||||
@api.one
|
||||
def confirm(self):
|
||||
"""
|
||||
cashmove_ref = self.pool.get('lunch.cashmove')
|
||||
for order_line in self.browse(cr, uid, ids, context=context):
|
||||
if order_line.state != 'confirmed':
|
||||
values = {
|
||||
'user_id': order_line.user_id.id,
|
||||
'amount': -order_line.price,
|
||||
'description': order_line.product_id.name,
|
||||
'order_id': order_line.id,
|
||||
'state': 'order',
|
||||
'date': order_line.date,
|
||||
}
|
||||
cashmove_ref.create(cr, uid, values, context=context)
|
||||
order_line.write({'state': 'confirmed'})
|
||||
return self._update_order_lines(cr, uid, ids, context=context)
|
||||
confirm one or more order line, update order status and create new cashmove
|
||||
"""
|
||||
if self.state != 'confirmed':
|
||||
values = {
|
||||
'user_id': self.user_id.id,
|
||||
'amount': -self.price,
|
||||
'description': self.product_id.name,
|
||||
'order_id': self.id,
|
||||
'state': 'order',
|
||||
'date': self.date,
|
||||
}
|
||||
self.env['lunch.cashmove'].create(values)
|
||||
self.state = 'confirmed'
|
||||
|
||||
def _update_order_lines(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Update the state of lunch.order based on its orderlines
|
||||
"""
|
||||
orders_ref = self.pool.get('lunch.order')
|
||||
orders = []
|
||||
for order_line in self.browse(cr, uid, ids, context=context):
|
||||
orders.append(order_line.order_id)
|
||||
for order in set(orders):
|
||||
isconfirmed = True
|
||||
for orderline in order.order_line_ids:
|
||||
if orderline.state == 'new':
|
||||
isconfirmed = False
|
||||
if orderline.state == 'cancelled':
|
||||
isconfirmed = False
|
||||
orders_ref.write(cr, uid, [order.id], {'state': 'partially'}, context=context)
|
||||
if isconfirmed:
|
||||
orders_ref.write(cr, uid, [order.id], {'state': 'confirmed'}, context=context)
|
||||
return {}
|
||||
|
||||
def cancel(self, cr, uid, ids, context=None):
|
||||
@api.one
|
||||
def cancel(self):
|
||||
"""
|
||||
cancel one or more order.line, update order status and unlink existing cashmoves
|
||||
"""
|
||||
cashmove_ref = self.pool.get('lunch.cashmove')
|
||||
self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
|
||||
for order_line in self.browse(cr, uid, ids, context=context):
|
||||
cash_ids = [cash.id for cash in order_line.cashmove]
|
||||
cashmove_ref.unlink(cr, uid, cash_ids, context=context)
|
||||
return self._update_order_lines(cr, uid, ids, context=context)
|
||||
|
||||
def _get_line_order_ids(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
return the list of lunch.order.lines ids to which belong the lunch.order 'ids'
|
||||
"""
|
||||
result = set()
|
||||
for lunch_order in self.browse(cr, uid, ids, context=context):
|
||||
for lines in lunch_order.order_line_ids:
|
||||
result.add(lines.id)
|
||||
return list(result)
|
||||
|
||||
_columns = {
|
||||
'name': fields.related('product_id', 'name', readonly=True),
|
||||
'order_id': fields.many2one('lunch.order', 'Order', ondelete='cascade'),
|
||||
'product_id': fields.many2one('lunch.product', 'Product', required=True),
|
||||
'date': fields.related('order_id', 'date', type='date', string="Date", readonly=True, store={
|
||||
'lunch.order': (_get_line_order_ids, ['date'], 10),
|
||||
'lunch.order.line': (lambda self, cr, uid, ids, ctx: ids, [], 10),
|
||||
}),
|
||||
'supplier': fields.related('product_id', 'supplier', type='many2one', relation='res.partner', string="Supplier", readonly=True, store=True),
|
||||
'user_id': fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True),
|
||||
'note': fields.text('Note'),
|
||||
'price': fields.float("Price"),
|
||||
'state': fields.selection([('new', 'New'), \
|
||||
('confirmed', 'Received'), \
|
||||
('ordered', 'Ordered'), \
|
||||
('cancelled', 'Cancelled')], \
|
||||
'Status', readonly=True, select=True),
|
||||
'cashmove': fields.one2many('lunch.cashmove', 'order_id', 'Cash Move', ondelete='cascade'),
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'new',
|
||||
}
|
||||
self.state = 'cancelled'
|
||||
self.cashmove.unlink()
|
||||
|
||||
|
||||
class lunch_product(osv.Model):
|
||||
"""
|
||||
lunch product
|
||||
"""
|
||||
class LunchProduct(models.Model):
|
||||
""" Products available to order. A product is linked to a specific supplier. """
|
||||
_name = 'lunch.product'
|
||||
_description = 'lunch product'
|
||||
_columns = {
|
||||
'name': fields.char('Product', required=True),
|
||||
'category_id': fields.many2one('lunch.product.category', 'Category', required=True),
|
||||
'description': fields.text('Description', size=256),
|
||||
'price': fields.float('Price', digits=(16,2)), #TODO: use decimal precision of 'Account', move it from product to decimal_precision
|
||||
'supplier': fields.many2one('res.partner', 'Supplier'),
|
||||
}
|
||||
|
||||
class lunch_product_category(osv.Model):
|
||||
"""
|
||||
lunch product category
|
||||
"""
|
||||
name = fields.Char('Product', required=True)
|
||||
category_id = fields.Many2one('lunch.product.category', 'Category', required=True)
|
||||
description = fields.Text('Description')
|
||||
price = fields.Float('Price', digits_compute=dp.get_precision('Account'))
|
||||
supplier = fields.Many2one('res.partner', 'Supplier')
|
||||
|
||||
|
||||
class LunchProductCategory(models.Model):
|
||||
""" Category of the product such as pizza, sandwich, pasta, chinese, burger... """
|
||||
_name = 'lunch.product.category'
|
||||
_description = 'lunch product category'
|
||||
_columns = {
|
||||
'name': fields.char('Category', required=True), #such as PIZZA, SANDWICH, PASTA, CHINESE, BURGER, ...
|
||||
}
|
||||
|
||||
class lunch_cashmove(osv.Model):
|
||||
"""
|
||||
lunch cashmove => order or payment
|
||||
"""
|
||||
name = fields.Char('Category', required=True)
|
||||
|
||||
|
||||
class LunchCashMove(models.Model):
|
||||
""" Two types of cashmoves: payment (credit) or order (debit) """
|
||||
_name = 'lunch.cashmove'
|
||||
_description = 'lunch cashmove'
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users', 'User Name', required=True),
|
||||
'date': fields.date('Date', required=True),
|
||||
'amount': fields.float('Amount', required=True), #depending on the kind of cashmove, the amount will be positive or negative
|
||||
'description': fields.text('Description'), #the description can be an order or a payment
|
||||
'order_id': fields.many2one('lunch.order.line', 'Order', ondelete='cascade'),
|
||||
'state': fields.selection([('order','Order'), ('payment','Payment')], 'Is an order or a Payment'),
|
||||
}
|
||||
_defaults = {
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
'date': fields.date.context_today,
|
||||
'state': 'payment',
|
||||
}
|
||||
|
||||
class lunch_alert(osv.Model):
|
||||
"""
|
||||
lunch alert
|
||||
"""
|
||||
user_id = fields.Many2one('res.users', 'User', required=True,
|
||||
default=lambda self: self.env.uid)
|
||||
date = fields.Date('Date', required=True, default=fields.Date.context_today)
|
||||
amount = fields.Float('Amount', required=True, help='Can be positive (payment) or negative (order or payment if user wants to get his money back)')
|
||||
description = fields.Text('Description', help='Can be an order or a payment')
|
||||
order_id = fields.Many2one('lunch.order.line', 'Order', ondelete='cascade')
|
||||
state = fields.Selection([('order', 'Order'), ('payment', 'Payment')],
|
||||
'Is an order or a payment', default='payment')
|
||||
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
return [(cashmove.id, '%s %s' % (_('Lunch Cashmove'), '#%d' % cashmove.id)) for cashmove in self]
|
||||
|
||||
|
||||
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'
|
||||
_columns = {
|
||||
'message': fields.text('Message', size=256, required=True),
|
||||
'alter_type': fields.selection([('specific', 'Specific Day'), \
|
||||
('week', 'Every Week'), \
|
||||
('days', 'Every Day')], \
|
||||
string='Recurrency', required=True, select=True),
|
||||
'specific_day': fields.date('Day'),
|
||||
'monday': fields.boolean('Monday'),
|
||||
'tuesday': fields.boolean('Tuesday'),
|
||||
'wednesday': fields.boolean('Wednesday'),
|
||||
'thursday': fields.boolean('Thursday'),
|
||||
'friday': fields.boolean('Friday'),
|
||||
'saturday': fields.boolean('Saturday'),
|
||||
'sunday': fields.boolean('Sunday'),
|
||||
'active_from': fields.float('Between', required=True),
|
||||
'active_to': fields.float('And', required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'alter_type': 'specific',
|
||||
'specific_day': fields.date.context_today,
|
||||
'active_from': 7,
|
||||
'active_to': 23,
|
||||
}
|
||||
|
||||
display = fields.Boolean(compute='_compute_display_get')
|
||||
message = fields.Text('Message', required=True)
|
||||
alert_type = fields.Selection([('specific', 'Specific Day'),
|
||||
('week', 'Every Week'),
|
||||
('days', 'Every Day')],
|
||||
string='Recurrency', required=True, select=True, default='specific')
|
||||
specific_day = fields.Date('Day', default=fields.Date.context_today)
|
||||
monday = fields.Boolean('Monday')
|
||||
tuesday = fields.Boolean('Tuesday')
|
||||
wednesday = fields.Boolean('Wednesday')
|
||||
thursday = fields.Boolean('Thursday')
|
||||
friday = fields.Boolean('Friday')
|
||||
saturday = fields.Boolean('Saturday')
|
||||
sunday = fields.Boolean('Sunday')
|
||||
start_hour = fields.Float('Between', oldname='active_from', required=True, default=7)
|
||||
end_hour = fields.Float('And', oldname='active_to', required=True, default=23)
|
||||
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
return [(alert.id, '%s %s' % (_('Alert'), '#%d' % alert.id)) for alert in self]
|
||||
|
||||
@api.one
|
||||
def _compute_display_get(self):
|
||||
"""
|
||||
This method check if the alert can be displayed today
|
||||
if alert type is specific : compare specific_day(date) with today's date
|
||||
if alert type is week : check today is set as alert (checkbox true) eg. self['monday']
|
||||
if alert type is day : True
|
||||
return : Message if can_display_alert is True else False
|
||||
"""
|
||||
|
||||
can_display_alert = {
|
||||
'specific': (self.specific_day == fields.Date.context_today(self)),
|
||||
'week': self[datetime.datetime.now().strftime('%A').lower()],
|
||||
'days': True
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if from_alert <= mynow.time() <= to_alert:
|
||||
self.display = True
|
||||
else:
|
||||
self.display = False
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import order
|
||||
import report_lunch_order
|
||||
@@ -1,79 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="report_lunchorder">
|
||||
<t t-call="report.html_container">
|
||||
<t t-call="report.external_layout">
|
||||
<div class="page">
|
||||
<div class="oe_structure"/>
|
||||
<odoo>
|
||||
<template id="report_lunch_order">
|
||||
<t t-call="report.html_container">
|
||||
<t t-call="report.external_layout">
|
||||
<div class="page">
|
||||
<div class="oe_structure"/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-5 col-xs-offset-7">
|
||||
<div t-field="user.partner_id"
|
||||
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}' />
|
||||
<div class="row">
|
||||
<div class="col-xs-5 col-xs-offset-7">
|
||||
<div t-field="user.partner_id"
|
||||
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Lunch Order</h2>
|
||||
<h2>Lunch Order</h2>
|
||||
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name/Date</th>
|
||||
<th>Order</th>
|
||||
<th>Description</th>
|
||||
<th class="text-right">Unit Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="get_users(docs)" t-as="o">
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<strong t-field="o.name"/>
|
||||
</td>
|
||||
<td class="text-right" colspan="2">
|
||||
<strong>
|
||||
<span t-esc="get_total(o, docs)"/>
|
||||
<span t-field="o.company_id.currency_id.symbol"/>
|
||||
</strong>
|
||||
</td>
|
||||
<th>Name/Date</th>
|
||||
<th>Order</th>
|
||||
<th>Description</th>
|
||||
<th class="text-right">Unit Price</th>
|
||||
</tr>
|
||||
<tr t-foreach="get_lines(o, docs)" t-as="lines">
|
||||
<td>
|
||||
<span t-field="lines.date"></span>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="lines.product_id.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="lines.note"/>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span t-field="lines.price"
|
||||
t-field-options='{"widget": "monetary", "display_currency": "o.company_id.currency_id"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="docs.read_group([('id', 'in', docs.ids)],['user_id'],['user_id'])" t-as="o">
|
||||
<t t-set="user" t-value="user.browse(o['user_id'][0])"/>
|
||||
<t t-set="lines" t-value="docs.search([('user_id', '=', user.id), ('id', 'in', docs.ids)])"/>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<strong t-field="user.name"/>
|
||||
</td>
|
||||
<td class="text-right" colspan="2">
|
||||
<strong>
|
||||
<span t-esc="sum(line.price for line in lines)"/>
|
||||
<span t-field="user.company_id.currency_id.symbol"/>
|
||||
</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-foreach="lines" t-as="line">
|
||||
<td>
|
||||
<span t-field="line.date"></span>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="line.product_id.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="line.note"/>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span t-field="line.price"
|
||||
t-field-options='{"widget": "monetary", "display_currency": "user.company_id.currency_id"}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-4 pull-right">
|
||||
<table class="table table-condensed">
|
||||
<tr class="border-black">
|
||||
<td><strong>Total</strong></td>
|
||||
<td class="text-right">
|
||||
<span t-esc="formatLang(get_nettotal(), currency_obj=res_company.currency_id)"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-xs-4 pull-right">
|
||||
<table class="table table-condensed">
|
||||
<tr class="border-black">
|
||||
<td><strong>Total</strong></td>
|
||||
<td class="text-right">
|
||||
<span t-esc="sum([line.price for line in docs]) or 0.0"/>
|
||||
<span t-field="user.company_id.currency_id.symbol"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<report
|
||||
id="action_report_lunch_order"
|
||||
string="Lunch Order"
|
||||
model="lunch.order.line"
|
||||
report_type="qweb-pdf"
|
||||
name="lunch.report_lunch_order"
|
||||
file="lunch.report_lunch_order"
|
||||
/>
|
||||
</odoo>
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<report
|
||||
id="action_report_lunch_order"
|
||||
string="Lunch Order"
|
||||
model="lunch.order.line"
|
||||
report_type="qweb-pdf"
|
||||
name="lunch.report_lunchorder"
|
||||
file="lunch.report_lunchorder"
|
||||
/>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,80 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
from openerp.report import report_sxw
|
||||
from openerp.osv import osv
|
||||
|
||||
|
||||
class order(report_sxw.rml_parse):
|
||||
|
||||
def get_lines(self, user,objects):
|
||||
lines=[]
|
||||
for obj in objects:
|
||||
if user.id==obj.user_id.id:
|
||||
lines.append(obj)
|
||||
return lines
|
||||
|
||||
def get_total(self, user,objects):
|
||||
lines=[]
|
||||
for obj in objects:
|
||||
if user.id==obj.user_id.id:
|
||||
lines.append(obj)
|
||||
total=0.0
|
||||
for line in lines:
|
||||
total+=line.price
|
||||
self.net_total+=total
|
||||
return total
|
||||
|
||||
def get_nettotal(self):
|
||||
return self.net_total
|
||||
|
||||
def get_users(self, objects):
|
||||
users=[]
|
||||
for obj in objects:
|
||||
if obj.user_id not in users:
|
||||
users.append(obj.user_id)
|
||||
return users
|
||||
|
||||
def get_note(self,objects):
|
||||
notes=[]
|
||||
for obj in objects:
|
||||
notes.append(obj.note)
|
||||
return notes
|
||||
|
||||
def __init__(self, cr, uid, name, context):
|
||||
super(order, self).__init__(cr, uid, name, context)
|
||||
self.net_total=0.0
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'get_lines': self.get_lines,
|
||||
'get_users': self.get_users,
|
||||
'get_total': self.get_total,
|
||||
'get_nettotal': self.get_nettotal,
|
||||
'get_note': self.get_note,
|
||||
})
|
||||
|
||||
|
||||
class report_lunchorder(osv.AbstractModel):
|
||||
_name = 'report.lunch.report_lunchorder'
|
||||
_inherit = 'report.abstract_report'
|
||||
_template = 'lunch.report_lunchorder'
|
||||
_wrapped_report_class = order
|
||||
@@ -1,62 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import tools
|
||||
from openerp.osv import fields,osv
|
||||
|
||||
class report_lunch_order(osv.osv):
|
||||
_name = "report.lunch.order.line"
|
||||
_description = "Lunch Orders Statistics"
|
||||
_auto = False
|
||||
_rec_name = 'date'
|
||||
_columns = {
|
||||
'date': fields.date('Date Order', readonly=True, select=True),
|
||||
'year': fields.char('Year', size=4, readonly=True),
|
||||
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
|
||||
('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
|
||||
('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
|
||||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'user_id': fields.many2one('res.users', 'User Name'),
|
||||
'price_total':fields.float('Total Price', readonly=True),
|
||||
'note' : fields.text('Note', readonly=True),
|
||||
}
|
||||
_order = 'date desc'
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_lunch_order_line')
|
||||
cr.execute("""
|
||||
create or replace view report_lunch_order_line as (
|
||||
select
|
||||
min(lo.id) as id,
|
||||
lo.user_id as user_id,
|
||||
lo.date as date,
|
||||
to_char(lo.date, 'YYYY') as year,
|
||||
to_char(lo.date, 'MM') as month,
|
||||
to_char(lo.date, 'YYYY-MM-DD') as day,
|
||||
lo.note as note,
|
||||
sum(lp.price) as price_total
|
||||
|
||||
from
|
||||
lunch_order_line as lo
|
||||
left join lunch_product as lp on (lo.product_id = lp.id)
|
||||
group by
|
||||
lo.date,lo.user_id,lo.note
|
||||
)
|
||||
""")
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -11,6 +11,3 @@ cashmove_user,"Cashmove user",model_lunch_cashmove,group_lunch_user,1,0,0,0
|
||||
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
|
||||
alert_user,"Alert user",model_lunch_alert,group_lunch_user,1,0,0,0
|
||||
access_report_order_line,access_report_order_line,model_report_lunch_order_line,,1,1,1,1
|
||||
access_lunch_validation,access_lunch_validation,model_lunch_validation,,1,1,1,1
|
||||
access_lunch_cancel,access_lunch_cancel,model_lunch_cancel,,1,1,1,1
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" ?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
<record model="ir.module.category" id="module_lunch_category">
|
||||
<field name="name">Lunch</field>
|
||||
<field name="description">Helps you handle your lunch needs, if you are a manager you will be able to create new products, cashmoves and to confirm or cancel orders.</field>
|
||||
@@ -29,6 +28,4 @@
|
||||
<field name="groups" eval="[(4, ref('group_lunch_manager'))]"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,43 +1,28 @@
|
||||
@charset "utf-8";
|
||||
.openerp .oe_lunch .oe_lunch_alert textarea {
|
||||
background-color: #ffc7c7;
|
||||
padding: 10px;
|
||||
height: 1em;
|
||||
margin-bottom: 20px;
|
||||
.openerp .o_lunch .o_lunch_alert {
|
||||
height: 22px;
|
||||
}
|
||||
.openerp .oe_lunch button.oe_button_add {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
left: 3px;
|
||||
}
|
||||
.openerp .oe_lunch button.oe_button_plus {
|
||||
margin: -2px;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_30pc {
|
||||
.openerp .o_lunch .o_lunch_30pc {
|
||||
width: 30%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_30pc:nth-child(3) {
|
||||
.openerp .o_lunch .o_lunch_30pc:nth-child(3) {
|
||||
padding-right: 0;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_30pc {
|
||||
.openerp .o_lunch .o_lunch_30pc {
|
||||
padding-right: 5%;
|
||||
}
|
||||
.openerp .oe_lunch h2 {
|
||||
.openerp .o_lunch h2 {
|
||||
color: #7c7bad;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_button {
|
||||
float: right;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_vignette {
|
||||
.openerp .o_lunch .o_lunch_vignette {
|
||||
border-bottom: 1px solid #dddddd;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.openerp .oe_lunch .oe_lunch_vignette:last-child {
|
||||
.openerp .o_lunch .o_lunch_vignette:last-child {
|
||||
border: none;
|
||||
}
|
||||
.openerp .oe_lunch .oe_group_text_button {
|
||||
.openerp .o_lunch .oe_group_text_button {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,24 @@
|
||||
@charset "utf-8"
|
||||
|
||||
.openerp
|
||||
.oe_lunch
|
||||
.oe_lunch_alert
|
||||
textarea
|
||||
background-color: #ffc7c7
|
||||
padding: 10px
|
||||
height: 1em
|
||||
margin-bottom: 20px
|
||||
button.oe_button_add
|
||||
position: relative
|
||||
top: -2px
|
||||
left: 3px
|
||||
button.oe_button_plus
|
||||
margin: -2px
|
||||
.oe_lunch_30pc
|
||||
.o_lunch
|
||||
.o_lunch_alert
|
||||
height: 22px
|
||||
.o_lunch_30pc
|
||||
width: 30%
|
||||
display: inline-block
|
||||
vertical-align: top
|
||||
.oe_lunch_30pc:nth-child(3)
|
||||
.o_lunch_30pc:nth-child(3)
|
||||
padding-right: 0
|
||||
.oe_lunch_30pc
|
||||
.o_lunch_30pc
|
||||
padding-right: 5%
|
||||
h2
|
||||
color: #7C7BAD
|
||||
.oe_lunch_button
|
||||
float: right
|
||||
.oe_lunch_vignette
|
||||
.o_lunch_vignette
|
||||
border-bottom: 1px solid #dddddd
|
||||
padding-top: 5px
|
||||
padding-bottom: 5px
|
||||
.oe_lunch_vignette:last-child
|
||||
.o_lunch_vignette:last-child
|
||||
border: none
|
||||
.oe_group_text_button
|
||||
margin-bottom: 3px
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
odoo.define('lunch.form_widgets', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var Model = require('web.Model');
|
||||
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 QWeb = core.qweb;
|
||||
var lunch = {};
|
||||
|
||||
lunch.lunch_order_widget_previous_orders = form_relational.AbstractManyField.extend(form_common.ReinitializeWidgetMixin, {
|
||||
template : 'lunch_order_widget_previous_orders',
|
||||
events: {
|
||||
'click span.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)
|
||||
.done(function(data){
|
||||
_.each(data, function(order){
|
||||
self.lunch_data[order['id']] = order;
|
||||
});
|
||||
});
|
||||
},
|
||||
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).attr('id')) );
|
||||
var order_line_ids = this.field_manager.fields.order_line_ids;
|
||||
order_line_ids.data_create(data);
|
||||
order_line_ids.reload_current_view();
|
||||
},
|
||||
render_value: function() {
|
||||
var self = this;
|
||||
return this.fetch_value().done(function(data) {
|
||||
if (_.isEmpty(data)) {
|
||||
return self.$el.html(QWeb.render("lunch_order_widget_no_previous_order"));
|
||||
}
|
||||
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();
|
||||
}
|
||||
});
|
||||
core.form_widget_registry.add('previous_order', lunch.lunch_order_widget_previous_orders);
|
||||
|
||||
return lunch;
|
||||
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates>
|
||||
<t t-name="lunch_order_widget_previous_orders">
|
||||
<div>
|
||||
<div class="previous_order_lines"></div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="lunch_order_widget_no_previous_order">
|
||||
<div class="oe_inline o_lunch_intro">
|
||||
<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 t-name="lunch_order_widget_previous_orders_list">
|
||||
<t t-foreach="categories" t-as="product_category">
|
||||
<div class="o_lunch_30pc">
|
||||
<h2><t t-esc="product_category"/></h2>
|
||||
<t t-foreach='categories[product_category]' t-as='product'>
|
||||
<div class="o_lunch_vignette">
|
||||
<span class="pull-right add_button oe_edit_only" t-att-id="product.id">
|
||||
<button type="button" class="oe_button oe_link">
|
||||
<span class="fa fa-plus-square"></span>
|
||||
<span>Add</span>
|
||||
</button>
|
||||
</span>
|
||||
<div class="oe_group_text_button">
|
||||
<div class="o_lunch_text">
|
||||
<t t-esc="product.product_id[1]"/>
|
||||
<span class="oe_tag">
|
||||
<t t-esc="widget.monetary.format_value(product.price)"/> <t t-esc="product.currency_id[1]"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-muted"><t t-if="product.note != false" t-esc="product.note"/></div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -1,22 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import test_lunch
|
||||
|
||||
import test_lunch
|
||||
|
||||
@@ -1,92 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import tools
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
class Test_Lunch(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
"""*****setUp*****"""
|
||||
super(Test_Lunch, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.res_users = self.registry('res.users')
|
||||
self.lunch_order = self.registry('lunch.order')
|
||||
self.lunch_order_line = self.registry('lunch.order.line')
|
||||
self.lunch_cashmove = self.registry('lunch.cashmove')
|
||||
self.lunch_product = self.registry('lunch.product')
|
||||
self.lunch_alert = self.registry('lunch.alert')
|
||||
self.lunch_product_category = self.registry('lunch.product.category')
|
||||
|
||||
self.demo_id = self.res_users.search(cr, uid, [('name', '=', 'Demo User')])
|
||||
self.product_bolognese_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'lunch', 'product_Bolognese')
|
||||
self.demo_user = self.env['res.users'].search([('name', '=', 'Demo User')])
|
||||
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.new_id_order = self.lunch_order.create(cr,uid,{
|
||||
'user_id': self.demo_id[0],
|
||||
'order_line_ids':'[]',
|
||||
},context=None)
|
||||
self.new_id_order_line = self.lunch_order_line.create(cr,uid,{
|
||||
'order_id':self.new_id_order,
|
||||
'product_id':self.product_Bolognese_id,
|
||||
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,
|
||||
'note': '+Emmental',
|
||||
'cashmove': [],
|
||||
'price': self.lunch_product.browse(cr,uid,self.product_Bolognese_id,context=None).price,
|
||||
'price': self.env['lunch.product'].browse(self.product_Bolognese_id).price,
|
||||
})
|
||||
|
||||
def test_00_lunch_order(self):
|
||||
"""Change the state of an order line from 'new' to 'ordered'. Check that there are no cashmove linked to that order line"""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None)
|
||||
self.order_one = self.new_id_order_line
|
||||
#we check that our order_line is a 'new' one and that there are no cashmove linked to that order_line:
|
||||
self.assertEqual(self.order_one.state,'new')
|
||||
self.assertEqual(self.order_one.state, 'new')
|
||||
self.assertEqual(list(self.order_one.cashmove), [])
|
||||
#we order that orderline so it's state will be 'ordered'
|
||||
self.order_one.order()
|
||||
self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None)
|
||||
self.order_one = self.new_id_order_line
|
||||
#we check that our order_line is a 'ordered' one and that there are no cashmove linked to that order_line:
|
||||
self.assertEqual(self.order_one.state,'ordered')
|
||||
self.assertEqual(self.order_one.state, 'ordered')
|
||||
self.assertEqual(list(self.order_one.cashmove), [])
|
||||
|
||||
def test_01_lunch_order(self):
|
||||
"""Change the state of an order line from 'new' to 'ordered' then to 'confirmed'. Check that there is a cashmove linked to the order line"""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.test_00_lunch_order()
|
||||
#We receive the order so we confirm the order line so it's state will be 'confirmed'
|
||||
#A cashmove will be created and we will test that the cashmove amount equals the order line price
|
||||
self.order_one.confirm()
|
||||
self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None)
|
||||
self.order_one = self.new_id_order_line
|
||||
#we check that our order_line is a 'confirmed' one and that there are a cashmove linked to that order_line with an amount equals to the order line price:
|
||||
self.assertEqual(self.order_one.state,'confirmed')
|
||||
self.assertEqual(self.order_one.state, 'confirmed')
|
||||
self.assertTrue(self.order_one.cashmove)
|
||||
self.assertTrue(self.order_one.cashmove[0].amount==-self.order_one.price)
|
||||
self.assertTrue(self.order_one.cashmove[0].amount == -self.order_one.price)
|
||||
|
||||
def test_02_lunch_order(self):
|
||||
"""Change the state of an order line from 'confirmed' to 'cancelled' and check that the cashmove linked to that order line will be deleted"""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.test_01_lunch_order()
|
||||
#We have a confirmed order with its associate cashmove
|
||||
#We execute the cancel function
|
||||
self.order_one.cancel()
|
||||
self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None)
|
||||
self.order_one = self.new_id_order_line
|
||||
#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)
|
||||
self.assertEqual(self.order_one.state, 'cancelled')
|
||||
self.assertFalse(self.order_one.cashmove)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="assets_backend" name="lunch assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/lunch/static/src/css/lunch.css"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
||||
<odoo>
|
||||
<template id="assets_backend" name="lunch assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/lunch/static/src/css/lunch.css"/>
|
||||
<script type="text/javascript" src="/lunch/static/src/js/lunch.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Top menu item -->
|
||||
<menuitem id='menu_lunch' name='Lunch' sequence="100" groups="group_lunch_user" icon="fa-cutlery"/>
|
||||
<menuitem name="Lunch" parent="menu_lunch" id="menu_lunch_title" sequence="50" />
|
||||
@@ -9,14 +8,14 @@
|
||||
<menuitem name="Configuration" parent="menu_lunch" id="menu_lunch_config" sequence="53" groups="group_lunch_manager"/>
|
||||
|
||||
<!--View Search to group/filter by Supplier and time-->
|
||||
<record model="ir.ui.view" id="lunch_order_line_search_view">
|
||||
<field name="name">Search</field>
|
||||
<record id="lunch_order_line_view_search" model="ir.ui.view">
|
||||
<field name="name">lunch.order.line.search</field>
|
||||
<field name="model">lunch.order.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search">
|
||||
<field name="name" filter_domain="['|', ('name', 'ilike', self), ('note', 'ilike', self)]"/>
|
||||
<filter name="not_confirmed" string="Not Received" domain="[('state','!=',('confirmed'))]"/>
|
||||
<filter name="comfirmed" string="Received" domain="[('state','=','confirmed')]"/>
|
||||
<filter name="confirmed" string="Received" domain="[('state','=','confirmed')]"/>
|
||||
<filter name="cancelled" string="Cancelled" domain="[('state','=','cancelled')]"/>
|
||||
<separator/>
|
||||
<filter name="today" string="Today" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
|
||||
@@ -30,8 +29,8 @@
|
||||
</record>
|
||||
|
||||
<!--View Search to group by employee and input/output (cashmoves)-->
|
||||
<record id="view_lunch_employee_payment_filter" model="ir.ui.view">
|
||||
<field name='name'>lunch employee payment</field>
|
||||
<record id="lunch_cashmove_view_search" model="ir.ui.view">
|
||||
<field name='name'>lunch.cashmove.search</field>
|
||||
<field name='model'>lunch.cashmove</field>
|
||||
<field name='arch' type='xml'>
|
||||
<search string="lunch employee payment">
|
||||
@@ -45,8 +44,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_lunch_cashmove_filter" model="ir.ui.view">
|
||||
<field name='name'>lunch cashmove</field>
|
||||
<record id="lunch_cashmove_view_search_2" model="ir.ui.view">
|
||||
<field name='name'>lunch.cashmove.search</field>
|
||||
<field name='model'>lunch.cashmove</field>
|
||||
<field name='arch' type='xml'>
|
||||
<search string="lunch cashmove">
|
||||
@@ -60,8 +59,8 @@
|
||||
</record>
|
||||
|
||||
<!--View search for order-->
|
||||
<record id="view_search_my_order" model="ir.ui.view">
|
||||
<field name='name'>lunch orders</field>
|
||||
<record id="lunch_order_view_search" model="ir.ui.view">
|
||||
<field name='name'>lunch.order.search</field>
|
||||
<field name='model'>lunch.order</field>
|
||||
<field name='arch' type='xml'>
|
||||
<search string="lunch orders">
|
||||
@@ -75,8 +74,8 @@
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="alert_search_view">
|
||||
<field name="name">Search</field>
|
||||
<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">
|
||||
@@ -86,8 +85,8 @@
|
||||
</record>
|
||||
|
||||
<!--view for cashmove-->
|
||||
<record model="ir.ui.view" id="casmove_tree_view">
|
||||
<field name="name">cashmove tree</field>
|
||||
<record id="lunch_cashmove_view_tree" model="ir.ui.view">
|
||||
<field name="name">lunch.cashmove.tree</field>
|
||||
<field name="model">lunch.cashmove</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="cashmove tree">
|
||||
@@ -99,8 +98,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="casmove_form_view">
|
||||
<field name="name">cashmove form</field>
|
||||
<record id="lunch_cashmove_view_form" model="ir.ui.view">
|
||||
<field name="name">lunch.cashmove.form</field>
|
||||
<field name="model">lunch.cashmove</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="cashmove form">
|
||||
@@ -120,22 +119,22 @@
|
||||
|
||||
|
||||
<!--Action for Your Orders-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_order_form">
|
||||
<record id="lunch_order_action_form" model="ir.actions.act_window">
|
||||
<field name="name">New Order</field>
|
||||
<field name="res_model">lunch.order</field>
|
||||
<field name="view_mode">form</field>
|
||||
</record>
|
||||
<menuitem name="New Order" parent="menu_lunch_title" id="menu_lunch_order_form" action="action_lunch_order_form" sequence="1"/>
|
||||
<menuitem name="New Order" parent="menu_lunch_title" id="lunch_order_menu_form" action="lunch_order_action_form" sequence="1"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_lunch_order_tree">
|
||||
<record id="lunch_order_action_tree" model="ir.actions.act_window">
|
||||
<field name="name">Your Orders</field>
|
||||
<field name="res_model">lunch.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_search_my_order"/>
|
||||
<field name="search_view_id" ref="lunch_order_view_search"/>
|
||||
<field name="context">{"search_default_is_mine":1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a lunch order.
|
||||
Click to create a lunch order.
|
||||
</p>
|
||||
<p>
|
||||
A lunch order is defined by its user, date and order lines.
|
||||
@@ -144,10 +143,10 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Previous Orders" parent="menu_lunch_title" id="menu_lunch_order_tree" action="action_lunch_order_tree" sequence="2"/>
|
||||
|
||||
<record model="ir.ui.view" id="casmove_tree">
|
||||
<field name="name">cashmove tree</field>
|
||||
<menuitem name="Previous Orders" parent="menu_lunch_title" id="lunch_order_menu_tree" action="lunch_order_action_tree" sequence="2"/>
|
||||
|
||||
<record id="lunch_cashmove_view_tree_2" model="ir.ui.view">
|
||||
<field name="name">lunch.cashmove.tree</field>
|
||||
<field name="model">lunch.cashmove</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="cashmove tree" create='false'>
|
||||
@@ -160,13 +159,13 @@
|
||||
</record>
|
||||
|
||||
<!--Action for Lunch cashmoves-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_cashmove_form">
|
||||
<record id="lunch_cashmove_action_account" model="ir.actions.act_window">
|
||||
<field name="name">Your Account</field>
|
||||
<field name="res_model">lunch.cashmove</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="search_view_id" ref="view_lunch_employee_payment_filter"/>
|
||||
<field name="search_view_id" ref="lunch_cashmove_view_search"/>
|
||||
<field name="context">{"search_default_is_mine_group":1}</field>
|
||||
<field name="view_id" ref="casmove_tree"/>
|
||||
<field name="view_id" ref="lunch_cashmove_view_tree_2"/>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
Here you can see your cash moves.<br/>A cash moves can be either an expense or a payment.
|
||||
@@ -174,14 +173,14 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Your Lunch Account" parent="menu_lunch_title" id="menu_lunch_cashmove_form" action="action_lunch_cashmove_form" sequence="3"/>
|
||||
<menuitem name="Your Lunch Account" parent="menu_lunch_title" id="lunch_cashmove_menu_form" action="lunch_cashmove_action_account" sequence="3"/>
|
||||
|
||||
<!--Action for Administrate Orders group by supplier-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_order_by_supplier_form">
|
||||
<record id="lunch_order_line_action_by_supplier" model="ir.actions.act_window">
|
||||
<field name="name">Orders by Supplier</field>
|
||||
<field name="res_model">lunch.order.line</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="search_view_id" ref="lunch_order_line_search_view"/>
|
||||
<field name="search_view_id" ref="lunch_order_line_view_search"/>
|
||||
<field name="context">{"search_default_group_by_supplier":1, "search_default_today":1}</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
@@ -194,14 +193,14 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Today's Orders by Supplier" parent="menu_lunch_admin" id="menu_lunch_order_by_supplier_form" action="action_lunch_order_by_supplier_form" />
|
||||
<menuitem name="Today's Orders by Supplier" parent="menu_lunch_admin" id="lunch_order_line_menu_by_supplier" action="lunch_order_line_action_by_supplier" />
|
||||
|
||||
<!--Action for control Supplier-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_control_suppliers">
|
||||
<record id="lunch_order_line_action_control_suppliers" model="ir.actions.act_window">
|
||||
<field name="name">Control Suppliers</field>
|
||||
<field name="res_model">lunch.order.line</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="search_view_id" ref="lunch_order_line_search_view"/>
|
||||
<field name="search_view_id" ref="lunch_order_line_view_search"/>
|
||||
<field name="context">{"search_default_group_by_date":1, "search_default_group_by_supplier":1}</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
@@ -214,19 +213,19 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Orders by Supplier" parent="menu_lunch_admin" id="menu_lunch_control_suppliers" action="action_lunch_control_suppliers" />
|
||||
<menuitem name="Orders by Supplier" parent="menu_lunch_admin" id="lunch_order_line_menu_control_suppliers" action="lunch_order_line_action_control_suppliers" />
|
||||
|
||||
<!--Action for Control Accounts-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_control_accounts">
|
||||
<record id="lunch_cashmove_action_control_accounts" model="ir.actions.act_window">
|
||||
<field name="name">Control Accounts</field>
|
||||
<field name="res_model">lunch.cashmove</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_lunch_cashmove_filter"/>
|
||||
<field name="search_view_id" ref="lunch_cashmove_view_search_2"/>
|
||||
<field name="context">{"search_default_group_by_user":1}</field>
|
||||
<field name="view_id" ref="casmove_tree_view"/>
|
||||
<field name="view_id" ref="lunch_cashmove_view_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new payment.
|
||||
Click to create a new payment.
|
||||
</p>
|
||||
<p>
|
||||
A cashmove can either be an expense or a payment.<br/>
|
||||
@@ -235,52 +234,52 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Control Accounts" parent="menu_lunch_cash" id="menu_lunch_control_accounts" action="action_lunch_control_accounts" />
|
||||
<menuitem name="Control Accounts" parent="menu_lunch_cash" id="lunch_cashmove_menu_control_accounts" action="lunch_cashmove_action_control_accounts" />
|
||||
|
||||
|
||||
<!--Action for Payment cashmove-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_cashmove">
|
||||
<record id="lunch_cashmove_action_payment" model="ir.actions.act_window">
|
||||
<field name="name">Register Cash Moves</field>
|
||||
<field name="res_model">lunch.cashmove</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="view_lunch_employee_payment_filter"/>
|
||||
<field name="search_view_id" ref="lunch_cashmove_view_search"/>
|
||||
<field name="context">{"search_default_is_payment":1}</field>
|
||||
<field name="view_id" ref="casmove_tree_view"/>
|
||||
<field name="view_id" ref="lunch_cashmove_view_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a payment.
|
||||
Click to create a payment.
|
||||
</p>
|
||||
<p>
|
||||
Here you can see the employees' payment. A payment is a cash move from the employee to the company.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Employee Payments" parent="menu_lunch_cash" id="menu_lunch_cashmove" action="action_lunch_cashmove" />
|
||||
<menuitem name="Employee Payments" parent="menu_lunch_cash" id="lunch_cashmove_menu_payment" action="lunch_cashmove_action_payment" />
|
||||
|
||||
<!--Action for Products-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_products">
|
||||
<record id="lunch_product_action" model="ir.actions.act_window">
|
||||
<field name="name">Products</field>
|
||||
<field name="res_model">lunch.product</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a product for lunch.
|
||||
Click to create a product for lunch.
|
||||
</p>
|
||||
<p>
|
||||
A product is defined by its name, category, price and supplier.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Products" parent="menu_lunch_config" id="menu_lunch_products" action="action_lunch_products" />
|
||||
<menuitem name="Products" parent="menu_lunch_config" id="lunch_product_menu" action="lunch_product_action" />
|
||||
|
||||
<!--Action for Product categories-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_product_categories">
|
||||
<record id="lunch_product_category_action" model="ir.actions.act_window">
|
||||
<field name="name">Product Categories</field>
|
||||
<field name="res_model">lunch.product.category</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a lunch category.
|
||||
Click to create a lunch category.
|
||||
</p>
|
||||
<p>
|
||||
Here you can find every lunch categories for products.
|
||||
@@ -288,7 +287,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="product_category_form_view">
|
||||
<record id="lunch_product_category_view_form" model="ir.ui.view">
|
||||
<field name="name">Product category Form</field>
|
||||
<field name="model">lunch.product.category</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -300,17 +299,17 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Product Categories" parent="menu_lunch_config" id="menu_lunch_product_categories" action="action_lunch_product_categories" />
|
||||
<menuitem name="Product Categories" parent="menu_lunch_config" id="lunch_product_category_menu" action="lunch_product_category_action" />
|
||||
|
||||
<!--Action for Alert-->
|
||||
<record model="ir.actions.act_window" id="action_lunch_alert">
|
||||
<record id="lunch_alert_action" model="ir.actions.act_window">
|
||||
<field name="name">Alerts</field>
|
||||
<field name="res_model">lunch.alert</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="alert_search_view"/>
|
||||
<field name="search_view_id" ref="lunch_alert_view_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a lunch alert.
|
||||
Click to create a lunch alert.
|
||||
</p>
|
||||
<p>
|
||||
Alerts are used to warn employee from possible issues concerning the lunch orders.
|
||||
@@ -324,31 +323,31 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem name="Alerts" parent="menu_lunch_config" id="menu_lunch_alert" action="action_lunch_alert" />
|
||||
<menuitem name="Alerts" parent="menu_lunch_config" id="lunch_alert_menu" action="lunch_alert_action" />
|
||||
|
||||
<!--View for Order lines-->
|
||||
<record model="ir.ui.view" id="orders_order_lines_tree_view">
|
||||
<field name="name">Order lines Tree</field>
|
||||
<record id="lunch_order_line_view_tree" model="ir.ui.view">
|
||||
<field name="name">lunch.order.line.tree</field>
|
||||
<field name="model">lunch.order.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Order lines Tree" create="false" edit="false">
|
||||
<field name='date'/>
|
||||
<field name='user_id'/>
|
||||
<field name='supplier' invisible='1'/>
|
||||
<field name='product_id'/>
|
||||
<field name='supplier' invisible='1'/>
|
||||
<field name='product_id'/>
|
||||
<field name='note'/>
|
||||
<field name='state'/>
|
||||
<field name='price' sum="Total"/>
|
||||
<button name="order" string="Order" type="object" icon="terp-call-start" attrs="{'invisible': ['|',('state','=','confirmed'),('state','=','ordered')]}"/>
|
||||
<button name="confirm" string="Confirm" type="object" icon="gtk-apply" attrs="{'invisible': [('state','!=','ordered')]}"/>
|
||||
<button name="confirm" string="Receive" type="object" icon="gtk-apply" attrs="{'invisible': [('state','!=','ordered')]}"/>
|
||||
<button name="cancel" string="Cancel" type="object" icon="gtk-cancel" attrs="{'invisible': [('state','=','cancelled')]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--View for Your orders-->
|
||||
<record model="ir.ui.view" id="orders_tree_view">
|
||||
<field name="name">Orders Tree View</field>
|
||||
<record id="lunch_order_view_tree" model="ir.ui.view">
|
||||
<field name="name">lunch.order.tree</field>
|
||||
<field name="model">lunch.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Orders Tree">
|
||||
@@ -360,12 +359,12 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="orders_form_view">
|
||||
<field name="name">Lunch Order</field>
|
||||
|
||||
<record id="lunch_order_view_form" model="ir.ui.view">
|
||||
<field name="name">lunch.order.form</field>
|
||||
<field name="model">lunch.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string='Orders Form' class="oe_lunch">
|
||||
<form string='Orders Form' class="o_lunch">
|
||||
<header>
|
||||
<field name='state' widget='statusbar' statusbar_visible='new,confirmed'/>
|
||||
</header>
|
||||
@@ -375,25 +374,24 @@
|
||||
<field name='user_id'
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'lunch.group_lunch_user']}"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name='date'/>
|
||||
</group>
|
||||
</group>
|
||||
<field name='alerts' attrs="{'invisible': ['|',('state','!=','new'),('alerts','=',False)]}" class="oe_inline oe_lunch_alert"/>
|
||||
<div name="preferences">
|
||||
</div>
|
||||
<field name='alerts' attrs="{'invisible': ['|',('state','!=','new'),('alerts','=',False)]}" class="oe_inline alert alert-danger"/>
|
||||
<field name='previous_order_ids' widget='previous_order'/>
|
||||
<separator string='Select your order'/>
|
||||
<field name='order_line_ids' nolabel='1' on_change='onchange_price(order_line_ids)'>
|
||||
<field name='order_line_ids' nolabel='1'>
|
||||
<tree string='List' editable='bottom'>
|
||||
<field name='product_id' on_change='onchange_price(product_id)'/>
|
||||
<field name='product_id'/>
|
||||
<field name='note' />
|
||||
<field name='price' on_change='onchange_price(product_id)'/>
|
||||
<field name='price'/>
|
||||
<field name='supplier' invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
<group class='oe_subtotal_footer oe_right'>
|
||||
<field name='total'/>
|
||||
<field name='total' widget='monetary' options="{'currency_field': 'currency_id'}"/>
|
||||
</group>
|
||||
<br/><br/>
|
||||
</sheet>
|
||||
@@ -402,8 +400,8 @@
|
||||
</record>
|
||||
|
||||
<!--View for Products-->
|
||||
<record model="ir.ui.view" id="products_tree_view">
|
||||
<field name="name">Products Tree</field>
|
||||
<record id="lunch_product_view_tree" model="ir.ui.view">
|
||||
<field name="name">lunch.product.tree</field>
|
||||
<field name="model">lunch.product</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Products Tree">
|
||||
@@ -416,8 +414,8 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="products_form_view">
|
||||
<field name="name">Products Form</field>
|
||||
<record id="lunch_product_view_form" model="ir.ui.view">
|
||||
<field name="name">lunch.product.form</field>
|
||||
<field name="model">lunch.product</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Products Form">
|
||||
@@ -440,31 +438,31 @@
|
||||
</record>
|
||||
|
||||
<!--view for alerts-->
|
||||
<record model="ir.ui.view" id="alert_tree_view">
|
||||
<field name="name">alert tree</field>
|
||||
<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 string="alert tree">
|
||||
<field name="message"/>
|
||||
<field name="alter_type"/>
|
||||
<field name='active_from' widget='float_time'/>
|
||||
<field name='active_to' widget='float_time'/>
|
||||
<field name="alert_type"/>
|
||||
<field name='start_hour' widget='float_time'/>
|
||||
<field name='end_hour' widget='float_time'/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="alert_form_view">
|
||||
<field name="name">alert form</field>
|
||||
<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 tree">
|
||||
<group string="Schedule Date">
|
||||
<group>
|
||||
<field name="alter_type" class="oe_inline"/>
|
||||
<field name="specific_day" attrs="{'invisible': [('alter_type','!=','specific')], 'required':[('alter_type','=','specific')]}"/>
|
||||
<field name="alert_type" class="oe_inline"/>
|
||||
<field name="specific_day" attrs="{'invisible': [('alert_type','!=','specific')], 'required':[('alert_type','=','specific')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('alter_type','!=','week')]}">
|
||||
<group attrs="{'invisible': [('alert_type','!=','week')]}">
|
||||
<group>
|
||||
<field name="monday"/>
|
||||
<field name="tuesday"/>
|
||||
@@ -478,8 +476,8 @@
|
||||
</group>
|
||||
</group>
|
||||
<group string="Schedule Hour">
|
||||
<field name='active_from' widget='float_time'/>
|
||||
<field name='active_to' widget='float_time'/>
|
||||
<field name='start_hour' widget='float_time'/>
|
||||
<field name='end_hour' widget='float_time'/>
|
||||
</group>
|
||||
<group string='Message'>
|
||||
<field name='message' nolabel='1' placeholder="Write the message you want to display during the defined period..."/>
|
||||
@@ -488,5 +486,4 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import lunch_validation
|
||||
import lunch_cancel
|
||||
import lunch_order
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
class lunch_cancel(osv.Model):
|
||||
""" lunch cancel """
|
||||
_name = 'lunch.cancel'
|
||||
_description = 'cancel lunch order'
|
||||
|
||||
def cancel(self,cr,uid,ids,context=None):
|
||||
return self.pool.get('lunch.order.line').cancel(cr, uid, ids, context=context)
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="cancel_order_lines_view">
|
||||
<field name="name">cancel order lines</field>
|
||||
<field name="model">lunch.cancel</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="cancel order lines">
|
||||
<separator string="Are you sure you want to cancel these meals?"/>
|
||||
<p class="oe_grey">
|
||||
Cancel a meal means that we didn't receive it from the supplier.
|
||||
<br/>
|
||||
A cancelled meal should not be paid by employees.
|
||||
</p>
|
||||
<footer>
|
||||
<button name="cancel" string="Cancel Orders" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="cancel_order_lines"
|
||||
multi="True"
|
||||
key2="client_action_multi" name="Cancel meals"
|
||||
res_model="lunch.cancel" src_model="lunch.order.line"
|
||||
view_mode="form" target="new" view_type="form" view_id="cancel_order_lines_view"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
class lunch_order_order(osv.TransientModel):
|
||||
""" lunch order meal """
|
||||
_name = 'lunch.order.order'
|
||||
_description = 'Wizard to order a meal'
|
||||
|
||||
def order(self,cr,uid,ids,context=None):
|
||||
return self.pool.get('lunch.order.line').order(cr, uid, ids, context=context)
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="order_order_lines_view">
|
||||
<field name="name">Order meal</field>
|
||||
<field name="model">lunch.order.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Order meal">
|
||||
<separator string="Are you sure you want to order these meals?"/>
|
||||
<p class="oe_grey">
|
||||
Order a meal doesn't mean that we have to pay it.
|
||||
A meal should be paid when it is received.
|
||||
</p>
|
||||
<footer>
|
||||
<button name="order" string="Order Meals" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button name="cancel" string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="order_order_lines"
|
||||
multi="True"
|
||||
key2="client_action_multi" name="Order meals"
|
||||
res_model="lunch.order.order" src_model="lunch.order.line"
|
||||
view_mode="form" target="new" view_type="form" view_id="order_order_lines_view"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
class lunch_validation(osv.Model):
|
||||
""" lunch validation """
|
||||
_name = 'lunch.validation'
|
||||
_description = 'lunch validation for order'
|
||||
|
||||
def confirm(self,cr,uid,ids,context=None):
|
||||
return self.pool.get('lunch.order.line').confirm(cr, uid, ids, context=context)
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="validate_order_lines_view">
|
||||
<field name="name">validate order lines</field>
|
||||
<field name="model">lunch.validation</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="validate order lines">
|
||||
<separator string="Did your received these meals?"/>
|
||||
<p class="oe_grey">
|
||||
Once a meal is received a new cash move is created for the employee.
|
||||
</p>
|
||||
<footer>
|
||||
<button name="confirm" string="Receive Meals" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button name="cancel" string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="validate_order_lines"
|
||||
multi="True"
|
||||
key2="client_action_multi" name="Receive meals"
|
||||
res_model="lunch.validation" src_model="lunch.order.line"
|
||||
view_mode="form" target="new" view_type="form" view_id="validate_order_lines_view"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1592,6 +1592,7 @@ core.form_tag_registry.add('button', WidgetButton);
|
||||
|
||||
return {
|
||||
FieldChar: FieldChar,
|
||||
FieldMonetary: FieldMonetary
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user