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 /addons/lunch/models | |
| 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
Diffstat (limited to 'addons/lunch/models')
| -rw-r--r-- | addons/lunch/models/__init__.py | 2 | ||||
| -rw-r--r-- | addons/lunch/models/lunch.py | 703 |
2 files changed, 241 insertions, 464 deletions
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 |
