bzr revid: api@openerp.com-20121031142448-4te52l1vfjtp5pqb
This commit is contained in:
Arnaud Pineux 2012-10-31 15:24:48 +01:00
parent a692a21546
commit 4c73fdc993
10 changed files with 161 additions and 66 deletions

View File

@ -32,7 +32,7 @@ The base module to manage lunch.
keep track for the Lunch Order, Cash Moves and Product. Apply Different
Category for the product.
""",
'data': ['security/groups.xml','lunch_view.xml','wizard/lunch_validation_view.xml','wizard/lunch_cancel_view.xml','lunch_report.xml',
'data': ['security/groups.xml','lunch_view.xml','wizard/lunch_order_view.xml','wizard/lunch_validation_view.xml','wizard/lunch_cancel_view.xml','lunch_report.xml',
'report/report_lunch_order_view.xml',
'security/ir.model.access.csv',],
'css':['static/src/css/lunch.css'],

View File

@ -20,12 +20,13 @@
#
##############################################################################
from xml.sax.saxutils import escape
import pytz
import time
from osv import osv, fields
from datetime import datetime, timedelta
from lxml import etree
from tools.translate import _
class lunch_order(osv.Model):
""" lunch order """
@ -38,19 +39,16 @@ class lunch_order(osv.Model):
for order in self.browse(cr, uid, ids, context=context):
value = 0.0
for orderline in order.order_line_ids:
if orderline.state != 'cancelled':
value += orderline.product_id.price
result[order.id]=value
value += orderline.product_id.price
result[order.id]=value
return result
def _compute_total(self, cr, uid, ids, name, context=None):
""" compute total"""
result= {}
value = 0.0
for order_line in self.browse(cr, uid, ids, context=context):
value+=order_line.price
result[order_line.order_id.id]=value
return result
result[order_line.order_id.id] = True
return result.keys()
def add_preference(self, cr, uid, ids, pref_id, context=None):
""" create a new order line based on the preference selected (pref_id)"""
@ -159,12 +157,19 @@ class lunch_order(osv.Model):
order_line_ids= self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context)
if order_line_ids:
tot = 0.0
product_ref = self.pool.get("lunch.product")
for prod in order_line_ids:
tot += prod['price']
if 'product_id' in prod:
tot += product_ref.browse(cr,uid,prod['product_id'],context=context).price
else:
tot += prod['price']
res = {'value':{'total':tot}}
return res
def create(self, cr, uid, values, context=None):
print "CREATE"
pref_ref = self.pool.get('lunch.preference')
pref_ids = pref_ref.search(cr,uid,[],context=context)
prod_ref = self.pool.get('lunch.product')
@ -176,15 +181,19 @@ class lunch_order(osv.Model):
for pref in pref_ref.browse(cr,uid,pref_ids,context=context):
if pref['product'].id == prods[2]['product_id']:
if pref['note'] == prods[2]['note']:
if pref['price'] == prods[2]['price']:
already_exists = True
if 'price' in prods[2]:
if pref['price'] == prods[2]['price']:
already_exists = True
else:
if pref['price'] == prod_ref.browse(cr,uid,prods[2]['product_id'])['price']:
already_exists = True
if already_exists == False:
new_pref = pref_ref.create(cr,uid,{'date':values['date'], 'color':0, 'order_id':new_id, 'user_id':values['user_id'], 'product': prods[2]['product_id'], 'product_name':prod_ref.browse(cr,uid,prods[2]['product_id'])['name'], 'note':prods[2]['note'], 'price':prods[2]['price']},context=context)
new_pref = pref_ref.create(cr,uid,{'date':values['date'], 'color':0, 'order_id':new_id, 'user_id':values['user_id'], 'product': prods[2]['product_id'], 'product_name':prod_ref.browse(cr,uid,prods[2]['product_id'])['name'], 'note':prods[2]['note'], 'price':prod_ref.browse(cr,uid,prods[2]['product_id'])['price']},context=context)
return new_id
def _default_preference_get(self,cr,uid,args,context=None):
""" return a maximum of 15 last user preferences ordered by date"""
return self.pool.get('lunch.preference').search(cr,uid,[('user_id','=',uid)],order='date desc',limit=15,context=context)
return self.pool.get('lunch.preference').search(cr,uid,[('user_id','=',uid)],order='date desc',limit=25,context=context)
def __getattr__(self, attr):
""" this method catch unexisting method call and if starts with
@ -198,7 +207,7 @@ class lunch_order(osv.Model):
return super(lunch_order,self).__getattr__(self,attr)
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
#TODO: not reviewed
""" 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)
if view_type == 'form':
pref_ref = self.pool.get("lunch.preference")
@ -208,22 +217,37 @@ class lunch_order(osv.Model):
pref_ids = pref_ref.search(cr,uid,[('user_id','=',uid)],context=context)
order_ids = order_ref.search(cr,uid,[('user_id','=',uid)],context=context)
if len(order_ids)>0:
text_xml = "<div>"
if len(order_ids)==0:
text_xml+="""
<div class="oe_inline oe_lunch_intro">
<div class="oe_lunch_intro_title">%s</div>
<br/>
%s
<br/>
%s
<br/>
%s
</div>
""" % (_("This is the first time you order a meal"),
_("Select a product and put your order comments on the note."),
_("Your favorite meals will be created based on your last orders."),
_("Don't forget the alerts displayed in the reddish area"))
else:
preferences = pref_ref.browse(cr,uid,pref_ids,context=context)
this_order = order_ref.browse(cr,uid,order_ids[0],context=context)
currency = currency_obj.browse(cr, uid, this_order['currency_id'], context=context)
categories = {} #store the different categories of products in preference
for pref in preferences:
categories[pref['product']['category_id']['name']]=[]
for pref in preferences:
categories[pref['product']['category_id']['name']].append(pref)
length = len(categories)
text_xml = """<div class="oe_lunch_view">"""
text_xml += """<separator name='pref' string='Favorites'/>"""
for key,value in categories.items():
text_xml+="""
<div class="oe_lunch_30pc">
<h2>%s</h2>
<div class="oe_lunch_30pc">
<h2>%s</h2>
""" % (key,)
i = 0
for val in value:
@ -233,7 +257,7 @@ class lunch_order(osv.Model):
text_xml+= '''
<div class="oe_lunch_vignette">
<span class="oe_lunch_button">
<button name="%s" class="oe_link oe_i oe_button_plus" type="object" string="+"></button><button name="%s" class="oe_link oe_button_add" type="object" string=" Add"></button>
<button name="%s" class="oe_link oe_i oe_button_plus" type="object" string="+"></button><button name="%s" class="oe_link oe_button_add" type="object" string="%s"></button>
</span>
<div class="oe_group_text_button">
<div class="oe_lunch_text">
@ -245,15 +269,15 @@ class lunch_order(osv.Model):
%s
</div>
</div>
''' % (function_name, function_name, val['product_name'], val['price'] or 0.0, currency['name'], val['note'] or '')
text_xml+= ('''</div>''')
text_xml+= ('''</div>''')
# ADD into ARCH xml
doc = etree.XML(res['arch'])
node = doc.xpath("//div[@name='preferences']")
to_add = etree.fromstring(text_xml)
node[0].append(to_add)
res['arch'] = etree.tostring(doc)
''' % (function_name, function_name,_("Add"), escape(val['product_name']), val['price'] or 0.0, currency['name'], escape(val['note']) or '')
text_xml+= '''</div>'''
# ADD into ARCH xml
text_xml += "</div>"
doc = etree.XML(res['arch'])
node = doc.xpath("//div[@name='preferences']")
to_add = etree.fromstring(text_xml)
node[0].append(to_add)
res['arch'] = etree.tostring(doc)
return res
_columns = {
@ -261,7 +285,7 @@ class lunch_order(osv.Model):
'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)]}), #TODO: a good naming convention is to finish your field names with `_ids´ for *2many fields. BTW, the field name should reflect more it's nature: `order_line_ids´ for example
'total' : fields.function(_price_get, string="Total",store={
'lunch.order.line': (_compute_total, ['price'], 20),
'lunch.order.line': (_compute_total, ['product_id','order_id'], 20),
}),
'state': fields.selection([('new', 'New'),('confirmed','Confirmed'), ('cancelled','Cancelled'), ('partially','Partially Confirmed')],'Status', readonly=True, select=True), #TODO: parcially? #TODO: the labels are confusing. confirmed=='received' or 'delivered'...
'alerts': fields.function(_alerts_get, string="Alerts", type='text'),
@ -291,6 +315,16 @@ class lunch_order_line(osv.Model):
return {'value': {'price': price}}
return {'value': {'price': 0.0}}
def _price_get(self,cr,uid,ids,name,arg,context=None):
result={}
for orderLine in self.browse(cr,uid,ids,context=context):
result[orderLine.id]=orderLine.product_id.price
return result
def order(self,cr,uid,ids,context=None):
for order_line in self.browse(cr,uid,ids,context=context):
self.write(cr,uid,[order_line.id],{'state':'ordered'},context)
return {}
def confirm(self,cr,uid,ids,context=None):
""" confirm one or more order line, update order status and create new cashmove """
@ -342,8 +376,8 @@ class lunch_order_line(osv.Model):
'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',size=256,required=False),
'price': fields.float('Price'),
'state': fields.selection([('new', 'New'),('confirmed','Confirmed'), ('cancelled','Cancelled')], \
'price' : fields.function(_price_get, type="float", string="Price",store=True),
'state': fields.selection([('new', 'New'),('confirmed','Received'), ('ordered','Ordered'), ('cancelled','Cancelled')], \
'Status', readonly=True, select=True), #new confirmed and cancelled are the convention
'cashmove': fields.one2many('lunch.cashmove','order_id','Cash Move',ondelete='cascade'),

View File

@ -2,7 +2,7 @@
<openerp>
<data>
<!--Menu and Title-->
<menuitem id='menu_lunch' name='Lunch' />
<menuitem id='menu_lunch' name='Lunch' sequence="300"/>
<menuitem name="Lunch Menu" parent="menu_lunch" id="menu_lunch_title" sequence="50" />
<menuitem name="Administrate Orders" parent="menu_lunch" id="menu_lunch_admin" sequence="51" groups="group_lunch_manager"/>
<menuitem name="Administrate Cash Moves" parent="menu_lunch" id="menu_lunch_cash" sequence="52" groups="group_lunch_manager"/>
@ -15,11 +15,13 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Search">
<field name="note"/>
<filter name="group_by_supplier" string="By Supplier" context="{'group_by':'supplier'}"/>
<filter name="not_confirmed" string="Not Confirmed" domain="[('state','!=',('confirmed'))]"/>
<filter name="comfirmed" string="Confirmed" domain="[('state','=','confirmed')]"/>
<filter name="not_confirmed" string="Not Received" domain="[('state','!=',('confirmed'))]"/>
<filter name="comfirmed" string="Received" domain="[('state','=','confirmed')]"/>
<filter name="cancelled" string="Cancelled" domain="[('state','=','cancelled')]"/>
<filter name="group_by_date" string="By Date" context="{'group_by':'date'}"/>
</search>
</field>
</record>
@ -29,6 +31,7 @@
<field name="model">lunch.order.line</field>
<field name="arch" type="xml">
<search string="Search Lunch Order">
<field name="note"/>
<filter name="group_by_supplier" string="By Supplier" context="{'group_by':'supplier'}"/>
<filter name="not_confirmed" string="Not Confirmed" domain="[('state','!=',('confirmed'))]"/>
<filter name="comfirmed" string="Confirmed" domain="[('state','=','confirmed')]"/>
@ -45,6 +48,7 @@
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch employee payment">
<field name="description"/>
<filter name='is_payment' string="Payment" domain="[('state','=','payment')]"/>
<filter name='is_mine' string="My Account" domain="[('user_id','=',uid)]"/>
</search>
@ -57,6 +61,7 @@
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch cashmove">
<field name="description"/>
<filter name='group_by_user' string="By Employee" context="{'group_by':'user_id'}"/>
</search>
</field>
@ -69,6 +74,7 @@
<field name='type'>search</field>
<field name='arch' type='xml'>
<search string="lunch orders">
<field name="date"/>
<filter name='is_mine' string="My Orders" domain="[('user_id','=',uid)]"/>
</search>
</field>
@ -93,8 +99,8 @@
Click to create a lunch order.
</p>
<p>
Use lunch order if you need to order any food for your lunch.
</p>
Select your favorite meals for today's lunch.
</p>
</field>
</record>
<menuitem name="Previous Orders" parent="menu_lunch_title" id="menu_lunch_order_tree" action="action_lunch_order_tree" sequence="2"/>
@ -108,7 +114,7 @@
<field name="context">{"search_default_is_mine":1}</field>
<field name="help" type="html">
<p>
Here you can see your cash moves. There are your orders and refund.
Here you can see your cash moves.<br/>A cash moves can be either an expense or a payment.
</p>
</field>
</record>
@ -123,7 +129,7 @@
<field name="context">{"search_default_group_by_supplier":1, "search_default_today":1}</field>
<field name="help" type="html">
<p>
Here you can see the orders of the day grouped by suppliers.
Here you can see today's orders grouped by suppliers.
</p>
</field>
</record>
@ -138,7 +144,7 @@
<field name="context">{"search_default_group_by_date":1, "search_default_group_by_supplier":1}</field>
<field name="help" type="html">
<p>
Here you can see the orders of the month grouped by suppliers.
Here you can see every orders grouped by suppliers and by date.
</p>
</field>
</record>
@ -153,11 +159,12 @@
<field name="context">{"search_default_group_by_user":1}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a transaction.
Click to create a new payment.
</p>
<p>
The different cash moves are used to see the orders but also the
employees' refunds.
A cashmove can either be an expense or a payment.<br/>
An expense is automatically created at the order receipt.<br/>
A payment represents the employee reimbursement to the company.
</p>
</field>
</record>
@ -176,7 +183,7 @@
Click to create a payment.
</p>
<p>
Here you can see the employees' refund.
Here you can see the employees' payment.
</p>
</field>
</record>
@ -192,7 +199,7 @@
Click to create a product for lunch.
</p>
<p>
A product is defined by its name, category, price and supplier.
A product is defined by its name, category, price and supplier (the supplier must be a lunch supplier).
</p>
</field>
</record>
@ -242,7 +249,8 @@
Click to create a lunch alert.
</p>
<p>
Alerts are used to warn employee and user from possible issues about the lunch.
Alerts are used to warn employee from possible issues concerning the lunch orders.<br/>
To create a lunch alert you have to define its recurrency (A specific day of the year, every week or every day), the time interval during which the alert should be executed and the message to display.
</p>
</field>
</record>
@ -262,7 +270,8 @@
<field name='note'/>
<field name='state'/>
<field name='price' sum="Total"/>
<button name="confirm" string="Confirm" type="object" icon="gtk-apply" attrs="{'invisible': [('state','=','confirmed')]}"/>
<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="cancel" string="Cancel" type="object" icon="gtk-cancel" attrs="{'invisible': [('state','=','cancelled')]}"/>
</tree>
</field>

View File

@ -5,6 +5,16 @@
height: 1em;
margin-bottom: 20px;
}
.openerp .oe_lunch .oe_lunch_intro {
text-align: center;
}
.openerp .oe_lunch .oe_lunch_intro_title {
font-size: 17px;
}
.openerp .oe_lunch button.oe_button_add {
position: relative;
top: -2px;

View File

@ -21,3 +21,4 @@
import lunch_validation
import lunch_cancel
import lunch_order

View File

@ -7,12 +7,12 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="cancel order lines" version="7.0">
<group>
<separator string="Are you sure you want to cancel these orders?"/>
<label string="Please note that: " colspan="4"/>
<label string="--------------------------" colspan="4"/>
<label string="Orders will not be deleted but will be cancelled" colspan="4"/>
</group>
<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
@ -24,7 +24,7 @@
<act_window id="cancel_order_lines"
multi="True"
key2="client_action_multi" name="Cancel"
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"/>

View File

@ -0,0 +1,14 @@
from osv import osv, fields
class lunch_order_order(osv.Model):
""" lunch order meal """
_name = 'lunch.order.order'
_description = 'Wizard to order a meal'
def order(self,cr,uid,ids,context=None):
order_lines_ref = self.pool.get('lunch.order.line')
active_ids = context.get('active_ids', [])
for order_line in order_lines_ref.browse(cr,uid,active_ids,context=context):
if order_line.state!='confirmed' and order_line.state!='ordered':
order_lines_ref.write(cr,uid,[order_line.id],{'state':'ordered'},context)
return {}

View File

@ -0,0 +1,31 @@
<?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="type">form</field>
<field name="arch" type="xml">
<form string="Order meal" version="7.0">
<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>

View File

@ -14,7 +14,7 @@ class lunch_validation(osv.Model):
for order in order_lines_ref.browse(cr,uid,order_ids,context=context):
if order.state!='confirmed':
new_id = cashmove_ref.create(cr,uid,{'user_id': order.user_id.id, 'amount':0 - order.price,'description':order.product.name, 'order_id':order.id, 'state':'order', 'date':order.date})
new_id = cashmove_ref.create(cr,uid,{'user_id': order.user_id.id, 'amount':0 - order.price,'description':order.product_id.name, 'order_id':order.id, 'state':'order', 'date':order.date})
order_lines_ref.write(cr,uid,[order.id],{'cashmove':[('0',new_id)], 'state':'confirmed'},context)
for order in order_lines_ref.browse(cr,uid,order_ids,context=context):
isconfirmed = True

View File

@ -7,16 +7,12 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="validate order lines" version="7.0">
<group>
<separator string="Are you sure you want to confirm these orders?"/>
<label string="Please note that: " colspan="4"/>
<label string="--------------------------" colspan="4"/>
<label string="Orders will only be confirmed if: " colspan="4"/>
<label string=" * Orders aren't already in the confirmed state" colspan="4"/>
<label string=" * Orders aren't in the cancelled state" colspan="4"/>
</group>
<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="Confirm Orders" type="object" class="oe_highlight"/>
<button name="confirm" string="Receive Meals" type="object" class="oe_highlight"/>
or
<button name="cancel" string="Cancel" class="oe_link" special="cancel" />
</footer>
@ -26,7 +22,7 @@
<act_window id="validate_order_lines"
multi="True"
key2="client_action_multi" name="Confirm"
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"/>