diff options
| author | Nicolas Martinelli <nim@odoo.com> | 2015-02-04 17:44:38 +0530 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2015-04-23 10:27:08 +0200 |
| commit | 3d63c15a567db74e9d65f47d9c7060527de7dcba (patch) | |
| tree | 5416144cfbf9bafacceaaf1ef09a784e2915a891 | |
| parent | 058d4033098c9a05439ee0d00876f34906984abb (diff) | |
[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
31 files changed, 689 insertions, 1169 deletions
diff --git a/addons/lunch/__init__.py b/addons/lunch/__init__.py index b0b18ae282c..908fbcb0107 100644 --- a/addons/lunch/__init__.py +++ b/addons/lunch/__init__.py @@ -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 diff --git a/addons/lunch/__openerp__.py b/addons/lunch/__openerp__.py index 0e0ff902338..21daff10461 100644 --- a/addons/lunch/__openerp__.py +++ b/addons/lunch/__openerp__.py @@ -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', diff --git a/addons/lunch/data/lunch_data.xml b/addons/lunch/data/lunch_data.xml new file mode 100644 index 00000000000..333cb5acbdf --- /dev/null +++ b/addons/lunch/data/lunch_data.xml @@ -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> diff --git a/addons/lunch/data/lunch_demo.xml b/addons/lunch/data/lunch_demo.xml index 546c21e0c22..bfe7dcc11f5 100644 --- a/addons/lunch/data/lunch_demo.xml +++ b/addons/lunch/data/lunch_demo.xml @@ -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> diff --git a/addons/lunch/models/__init__.py b/addons/lunch/models/__init__.py index 894fef6dee6..6a17f40da4a 100644 --- a/addons/lunch/models/__init__.py +++ b/addons/lunch/models/__init__.py @@ -1,3 +1,3 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- import lunch diff --git a/addons/lunch/models/lunch.py b/addons/lunch/models/lunch.py index 1d17b4468ac..4f572c6019a 100644 --- a/addons/lunch/models/lunch.py +++ b/addons/lunch/models/lunch.py @@ -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/>. -# -############################################################################## - -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 _ - -class lunch_order(osv.Model): - """ - lunch order (contains one or more lunch order line(s)) +# -*- coding: utf-8 -*- + +import datetime + +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 - - 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´ + self.total = sum( + orderline.price for orderline in self.order_line_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) + get the alerts to display on the order form """ - 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 + alert_msg = [alert.message + for alert in self.env['lunch.alert'].search([]) + if alert.display] + + 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): """ - 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 + Calculates the forecasted balance of the user, taking into account the current order """ - 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]] + prev_cashmove = self.env['lunch.cashmove'].search([('user_id', '=', self.user_id.id)]) + balance = sum(cashmove.amount for cashmove in prev_cashmove) - def can_display_alert(self, alert): - """ - This method check if the alert can be displayed today + 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): """ - 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 + Prevents the user to create an order in the past """ - 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) - - def onchange_price(self, cr, uid, ids, order_line_ids, context=None): + 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): """ - Onchange methode that refresh the total price of order + 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 """ - 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 + 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 - - 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 + isConfirmed = False + + 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, - } - - -class lunch_order_line(osv.Model): - """ - lunch order line: one lunch order can have many order lines - """ + self.state = 'new' + return + + +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}} - - def order(self, cr, uid, ids, context=None): - """ + 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') + + @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) - - def _update_order_lines(self, cr, uid, ids, context=None): + confirm one or more order line, update order status and create new cashmove """ - 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): + 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' + + @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', - } - - -class lunch_product(osv.Model): - """ - lunch product - """ + self.state = 'cancelled' + self.cashmove.unlink() + + +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 diff --git a/addons/lunch/report/__init__.py b/addons/lunch/report/__init__.py deleted file mode 100644 index ddaa3b45f8e..00000000000 --- a/addons/lunch/report/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- encoding: utf-8 -*- - -import order -import report_lunch_order diff --git a/addons/lunch/report/lunch_order_templates.xml b/addons/lunch/report/lunch_order_templates.xml index 30401bc142b..58af7ebdc46 100644 --- a/addons/lunch/report/lunch_order_templates.xml +++ b/addons/lunch/report/lunch_order_templates.xml @@ -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> - </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> + <th>Name/Date</th> + <th>Order</th> + <th>Description</th> + <th class="text-right">Unit Price</th> </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> diff --git a/addons/lunch/report/lunch_order_views.xml b/addons/lunch/report/lunch_order_views.xml new file mode 100644 index 00000000000..7ba774d8805 --- /dev/null +++ b/addons/lunch/report/lunch_order_views.xml @@ -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>
\ No newline at end of file diff --git a/addons/lunch/report/lunch_report_views.xml b/addons/lunch/report/lunch_report_views.xml deleted file mode 100644 index 990694af4a9..00000000000 --- a/addons/lunch/report/lunch_report_views.xml +++ /dev/null @@ -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> diff --git a/addons/lunch/report/order.py b/addons/lunch/report/order.py deleted file mode 100644 index ef5108ff567..00000000000 --- a/addons/lunch/report/order.py +++ /dev/null @@ -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 diff --git a/addons/lunch/report/report_lunch_order.py b/addons/lunch/report/report_lunch_order.py deleted file mode 100644 index ac201350142..00000000000 --- a/addons/lunch/report/report_lunch_order.py +++ /dev/null @@ -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 - ) - """) diff --git a/addons/lunch/report/report_lunch_order_view.xml b/addons/lunch/report/report_lunch_order_view.xml deleted file mode 100644 index f7bfdcd7395..00000000000 --- a/addons/lunch/report/report_lunch_order_view.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<openerp> - <data> - - - </data> -</openerp> diff --git a/addons/lunch/security/ir.model.access.csv b/addons/lunch/security/ir.model.access.csv index aa56786f626..244fbf11f18 100644 --- a/addons/lunch/security/ir.model.access.csv +++ b/addons/lunch/security/ir.model.access.csv @@ -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 diff --git a/addons/lunch/security/lunch_security.xml b/addons/lunch/security/lunch_security.xml index abdd0cea0a6..a4757302500 100644 --- a/addons/lunch/security/lunch_security.xml +++ b/addons/lunch/security/lunch_security.xml @@ -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> diff --git a/addons/lunch/static/src/css/lunch.css b/addons/lunch/static/src/css/lunch.css index 96e39c53fa6..3cafcbedfda 100644 --- a/addons/lunch/static/src/css/lunch.css +++ b/addons/lunch/static/src/css/lunch.css @@ -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 .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_alert { + height: 22px; +} +.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; } diff --git a/addons/lunch/static/src/css/lunch.sass b/addons/lunch/static/src/css/lunch.sass index 9612b5fdd3d..f8a31ec7f47 100644 --- a/addons/lunch/static/src/css/lunch.sass +++ b/addons/lunch/static/src/css/lunch.sass @@ -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 diff --git a/addons/lunch/static/src/js/lunch.js b/addons/lunch/static/src/js/lunch.js new file mode 100644 index 00000000000..116c24389c6 --- /dev/null +++ b/addons/lunch/static/src/js/lunch.js @@ -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; + +}); diff --git a/addons/lunch/static/src/xml/lunch.xml b/addons/lunch/static/src/xml/lunch.xml new file mode 100644 index 00000000000..66f9a806600 --- /dev/null +++ b/addons/lunch/static/src/xml/lunch.xml @@ -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> diff --git a/addons/lunch/tests/__init__.py b/addons/lunch/tests/__init__.py index fd218c34e65..a83148bcdce 100644 --- a/addons/lunch/tests/__init__.py +++ b/addons/lunch/tests/__init__.py @@ -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 diff --git a/addons/lunch/tests/test_lunch.py b/addons/lunch/tests/test_lunch.py index 2a2a6aa0ed7..6b7ea1f8461 100644 --- a/addons/lunch/tests/test_lunch.py +++ b/addons/lunch/tests/test_lunch.py @@ -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)
\ No newline at end of file + self.assertEqual(self.order_one.state, 'cancelled') + self.assertFalse(self.order_one.cashmove) diff --git a/addons/lunch/views/lunch_templates.xml b/addons/lunch/views/lunch_templates.xml index d7e7244d28c..e025fc01a03 100644 --- a/addons/lunch/views/lunch_templates.xml +++ b/addons/lunch/views/lunch_templates.xml @@ -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> diff --git a/addons/lunch/views/lunch_views.xml b/addons/lunch/views/lunch_views.xml index 818ac216be7..9ad4a7b8393 100644 --- a/addons/lunch/views/lunch_views.xml +++ b/addons/lunch/views/lunch_views.xml @@ -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> diff --git a/addons/lunch/wizard/__init__.py b/addons/lunch/wizard/__init__.py deleted file mode 100644 index 9af98b65899..00000000000 --- a/addons/lunch/wizard/__init__.py +++ /dev/null @@ -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 diff --git a/addons/lunch/wizard/lunch_cancel.py b/addons/lunch/wizard/lunch_cancel.py deleted file mode 100644 index 5da41175a56..00000000000 --- a/addons/lunch/wizard/lunch_cancel.py +++ /dev/null @@ -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) diff --git a/addons/lunch/wizard/lunch_cancel_view.xml b/addons/lunch/wizard/lunch_cancel_view.xml deleted file mode 100644 index 548dbcb299c..00000000000 --- a/addons/lunch/wizard/lunch_cancel_view.xml +++ /dev/null @@ -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> diff --git a/addons/lunch/wizard/lunch_order.py b/addons/lunch/wizard/lunch_order.py deleted file mode 100644 index aa595323c2e..00000000000 --- a/addons/lunch/wizard/lunch_order.py +++ /dev/null @@ -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) diff --git a/addons/lunch/wizard/lunch_order_view.xml b/addons/lunch/wizard/lunch_order_view.xml deleted file mode 100644 index df509013619..00000000000 --- a/addons/lunch/wizard/lunch_order_view.xml +++ /dev/null @@ -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> diff --git a/addons/lunch/wizard/lunch_validation.py b/addons/lunch/wizard/lunch_validation.py deleted file mode 100644 index e1e888ee399..00000000000 --- a/addons/lunch/wizard/lunch_validation.py +++ /dev/null @@ -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) diff --git a/addons/lunch/wizard/lunch_validation_view.xml b/addons/lunch/wizard/lunch_validation_view.xml deleted file mode 100644 index fee046c39a3..00000000000 --- a/addons/lunch/wizard/lunch_validation_view.xml +++ /dev/null @@ -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> diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js index 5f7e9afdf34..2539b0d7566 100644 --- a/addons/web/static/src/js/views/form_widgets.js +++ b/addons/web/static/src/js/views/form_widgets.js @@ -1592,6 +1592,7 @@ core.form_tag_registry.add('button', WidgetButton); return { FieldChar: FieldChar, + FieldMonetary: FieldMonetary }; }); |
