2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-24 12:09:06 +00:00
#
2009-10-14 11:15:34 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-06-16 11:00:21 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# 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.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# 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
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-24 12:09:06 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
from osv import fields , osv
from _common import rounding
2007-10-10 05:44:59 +00:00
import time
2007-10-24 06:13:33 +00:00
from tools import config
2008-12-29 14:55:49 +00:00
from tools . misc import ustr
2008-07-08 08:13:12 +00:00
from tools . translate import _
2010-03-06 20:52:19 +00:00
import decimal_precision as dp
2006-12-07 13:41:40 +00:00
class price_type ( osv . osv ) :
2008-07-22 15:11:28 +00:00
"""
The price type is used to points which field in the product form
is a price and in which currency is this price expressed .
When a field is a price , you can use it in pricelists to base
sale and purchase prices based on some fields of the product .
"""
2010-11-19 13:48:01 +00:00
def _price_field_get ( self , cr , uid , context = None ) :
2008-12-13 06:05:19 +00:00
mf = self . pool . get ( ' ir.model.fields ' )
ids = mf . search ( cr , uid , [ ( ' model ' , ' in ' , ( ( ' product.product ' ) , ( ' product.template ' ) ) ) , ( ' ttype ' , ' = ' , ' float ' ) ] , context = context )
2008-12-08 17:08:40 +00:00
res = [ ]
2008-12-13 06:05:19 +00:00
for field in mf . browse ( cr , uid , ids , context = context ) :
res . append ( ( field . name , field . field_description ) )
2008-12-08 17:08:40 +00:00
return res
2008-07-22 15:11:28 +00:00
def _get_currency ( self , cr , uid , ctx ) :
comp = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid ) . company_id
if not comp :
comp_id = self . pool . get ( ' res.company ' ) . search ( cr , uid , [ ] ) [ 0 ]
comp = self . pool . get ( ' res.company ' ) . browse ( cr , uid , comp_id )
return comp . currency_id . id
2007-10-23 19:02:01 +00:00
2008-07-22 15:11:28 +00:00
_name = " product.price.type "
2010-05-19 18:32:32 +00:00
_description = " Price Type "
2008-07-22 15:11:28 +00:00
_columns = {
2008-09-22 06:06:56 +00:00
" name " : fields . char ( " Price Name " , size = 32 , required = True , translate = True , help = " Name of this kind of price. " ) ,
2008-07-22 15:11:28 +00:00
" active " : fields . boolean ( " Active " ) ,
2009-01-06 11:17:44 +00:00
" field " : fields . selection ( _price_field_get , " Product Field " , size = 32 , required = True , help = " Associated field in the product form. " ) ,
2008-09-22 06:06:56 +00:00
" currency_id " : fields . many2one ( ' res.currency ' , " Currency " , required = True , help = " The currency the field is expressed in. " ) ,
2008-07-22 15:11:28 +00:00
}
_defaults = {
" active " : lambda * args : True ,
" currency_id " : _get_currency
}
2010-08-13 12:20:05 +00:00
2006-12-07 13:41:40 +00:00
price_type ( )
#----------------------------------------------------------
# Price lists
#----------------------------------------------------------
class product_pricelist_type ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " product.pricelist.type "
_description = " Pricelist Type "
_columns = {
2009-01-22 23:04:36 +00:00
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
2008-09-22 05:56:30 +00:00
' key ' : fields . char ( ' Key ' , size = 64 , required = True , help = " Used in the code to select specific prices based on the context. Keep unchanged. " ) ,
2008-07-22 15:11:28 +00:00
}
2006-12-07 13:41:40 +00:00
product_pricelist_type ( )
class product_pricelist ( osv . osv ) :
2010-11-19 13:48:01 +00:00
def _pricelist_type_get ( self , cr , uid , context = None ) :
2009-10-01 11:32:20 +00:00
pricelist_type_obj = self . pool . get ( ' product.pricelist.type ' )
pricelist_type_ids = pricelist_type_obj . search ( cr , uid , [ ] , order = ' name ' )
pricelist_types = pricelist_type_obj . read ( cr , uid , pricelist_type_ids , [ ' key ' , ' name ' ] , context = context )
2009-11-24 12:09:06 +00:00
2009-10-01 11:32:20 +00:00
res = [ ]
2009-11-24 12:09:06 +00:00
2009-10-01 11:32:20 +00:00
for type in pricelist_types :
res . append ( ( type [ ' key ' ] , type [ ' name ' ] ) )
2009-11-24 12:09:06 +00:00
2009-10-01 11:32:20 +00:00
return res
2010-08-13 12:20:05 +00:00
2008-07-22 15:11:28 +00:00
_name = " product.pricelist "
_description = " Pricelist "
_columns = {
2008-09-22 05:56:30 +00:00
' name ' : fields . char ( ' Pricelist Name ' , size = 64 , required = True , translate = True ) ,
2009-12-21 12:21:32 +00:00
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to true, it will allow you to hide the pricelist without removing it. " ) ,
2008-07-22 15:11:28 +00:00
' type ' : fields . selection ( _pricelist_type_get , ' Pricelist Type ' , required = True ) ,
' version_id ' : fields . one2many ( ' product.pricelist.version ' , ' pricelist_id ' , ' Pricelist Versions ' ) ,
' currency_id ' : fields . many2one ( ' res.currency ' , ' Currency ' , required = True ) ,
2009-12-02 11:20:06 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' ) ,
2008-07-22 15:11:28 +00:00
}
2009-11-24 12:09:06 +00:00
2010-11-19 13:48:01 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
2008-12-26 06:50:18 +00:00
result = [ ]
2009-03-09 13:35:04 +00:00
if not all ( ids ) :
return result
2010-11-19 13:48:01 +00:00
for pl in self . browse ( cr , uid , ids , context = context ) :
2008-12-29 16:33:26 +00:00
name = pl . name + ' ( ' + pl . currency_id . name + ' ) '
2008-12-26 06:50:18 +00:00
result . append ( ( pl . id , name ) )
2008-12-24 15:50:06 +00:00
return result
2009-11-24 12:09:06 +00:00
2008-12-24 15:50:06 +00:00
2008-07-22 15:11:28 +00:00
def _get_currency ( self , cr , uid , ctx ) :
2008-12-29 14:55:49 +00:00
comp = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid ) . company_id
2008-07-22 15:11:28 +00:00
if not comp :
comp_id = self . pool . get ( ' res.company ' ) . search ( cr , uid , [ ] ) [ 0 ]
comp = self . pool . get ( ' res.company ' ) . browse ( cr , uid , comp_id )
return comp . currency_id . id
2007-10-23 19:02:01 +00:00
2008-07-22 15:11:28 +00:00
_defaults = {
' active ' : lambda * a : 1 ,
" currency_id " : _get_currency
}
2006-12-07 13:41:40 +00:00
2010-09-29 09:57:42 +00:00
#def price_get_multi(self, cr, uid, product_ids, context=None):
def price_get_multi ( self , cr , uid , pricelist_ids , products_by_qty_by_partner , context = None ) :
""" multi products ' price_get ' .
@param pricelist_ids :
@param products_by_qty :
@param partner :
@param context : {
' date ' : Date of the pricelist ( % Y - % m - % d ) , }
@return : a dict of dict with product_id as key and a dict ' price by pricelist ' as value
"""
def _create_parent_category_list ( id , lst ) :
if not id :
return [ ]
parent = product_category_tree . get ( id )
if parent :
lst . append ( parent )
return _create_parent_category_list ( parent , lst )
else :
return lst
# _create_parent_category_list
if context is None :
context = { }
date = time . strftime ( ' % Y- % m- %d ' )
if ' date ' in context :
date = context [ ' date ' ]
currency_obj = self . pool . get ( ' res.currency ' )
product_obj = self . pool . get ( ' product.product ' )
product_category_obj = self . pool . get ( ' product.category ' )
product_uom_obj = self . pool . get ( ' product.uom ' )
supplierinfo_obj = self . pool . get ( ' product.supplierinfo ' )
price_type_obj = self . pool . get ( ' product.price.type ' )
product_pricelist_version_obj = self . pool . get ( ' product.pricelist.version ' )
# product.pricelist.version:
if pricelist_ids :
pricelist_version_ids = pricelist_ids
else :
# all pricelists:
pricelist_version_ids = product_pricelist_version_obj . search ( cr , uid , [ ] )
pricelist_version_ids = list ( set ( pricelist_version_ids ) )
plversions_search_args = [
( ' pricelist_id ' , ' in ' , pricelist_version_ids ) ,
' | ' ,
( ' date_start ' , ' = ' , False ) ,
( ' date_start ' , ' <= ' , date ) ,
' | ' ,
( ' date_end ' , ' = ' , False ) ,
( ' date_end ' , ' >= ' , date ) ,
]
plversion_ids = product_pricelist_version_obj . search ( cr , uid , plversions_search_args )
if len ( pricelist_version_ids ) != len ( plversion_ids ) :
msg = " At least one pricelist has no active version ! \n Please create or activate one. "
raise osv . except_osv ( _ ( ' Warning ! ' ) , _ ( msg ) )
# product.product:
product_ids = [ i [ 0 ] for i in products_by_qty_by_partner ]
#products = dict([(item['id'], item) for item in product_obj.read(cr, uid, product_ids, ['categ_id', 'product_tmpl_id', 'uos_id', 'uom_id'])])
products = product_obj . browse ( cr , uid , product_ids , context = context )
products_dict = dict ( [ ( item . id , item ) for item in products ] )
# product.category:
product_category_ids = product_category_obj . search ( cr , uid , [ ] )
product_categories = product_category_obj . read ( cr , uid , product_category_ids , [ ' parent_id ' ] )
product_category_tree = dict ( [ ( item [ ' id ' ] , item [ ' parent_id ' ] [ 0 ] ) for item in product_categories if item [ ' parent_id ' ] ] )
results = { }
for product_id , qty , partner in products_by_qty_by_partner :
for pricelist_id in pricelist_version_ids :
price = False
tmpl_id = products_dict [ product_id ] . product_tmpl_id and products_dict [ product_id ] . product_tmpl_id . id or False
categ_id = products_dict [ product_id ] . categ_id and products_dict [ product_id ] . categ_id . id or False
categ_ids = _create_parent_category_list ( categ_id , [ categ_id ] )
if categ_ids :
categ_where = ' (categ_id IN ( ' + ' , ' . join ( map ( str , categ_ids ) ) + ' )) '
else :
categ_where = ' (categ_id IS NULL) '
cr . execute (
' SELECT i.*, pl.currency_id '
' FROM product_pricelist_item AS i, '
' product_pricelist_version AS v, product_pricelist AS pl '
' WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s ) '
' AND (product_id IS NULL OR product_id = %s ) '
' AND ( ' + categ_where + ' OR (categ_id IS NULL)) '
' AND price_version_id = %s '
' AND (min_quantity IS NULL OR min_quantity <= %s ) '
' AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
' ORDER BY sequence ' ,
( tmpl_id , product_id , pricelist_id , qty ) )
res1 = cr . dictfetchall ( )
for res in res1 :
if res :
if res [ ' base ' ] == - 1 :
if not res [ ' base_pricelist_id ' ] :
price = 0.0
else :
price_tmp = self . price_get ( cr , uid ,
2010-10-04 08:18:03 +00:00
[ res [ ' base_pricelist_id ' ] ] , product_id ,
2010-09-29 09:57:42 +00:00
qty ) [ res [ ' base_pricelist_id ' ] ]
ptype_src = self . browse ( cr , uid , res [ ' base_pricelist_id ' ] ) . currency_id . id
price = currency_obj . compute ( cr , uid , ptype_src , res [ ' currency_id ' ] , price_tmp , round = False )
elif res [ ' base ' ] == - 2 :
# this section could be improved by moving the queries outside the loop:
where = [ ]
if partner :
where = [ ( ' name ' , ' = ' , partner ) ]
sinfo = supplierinfo_obj . search ( cr , uid ,
[ ( ' product_id ' , ' = ' , tmpl_id ) ] + where )
price = 0.0
if sinfo :
cr . execute ( ' SELECT * ' \
' FROM pricelist_partnerinfo ' \
' WHERE suppinfo_id IN %s ' \
' AND min_quantity <= %s ' \
' ORDER BY min_quantity DESC LIMIT 1 ' , ( tuple ( sinfo ) , qty , ) )
res2 = cr . dictfetchone ( )
if res2 :
price = res2 [ ' price ' ]
else :
price_type = price_type_obj . browse ( cr , uid , int ( res [ ' base ' ] ) )
price = currency_obj . compute ( cr , uid ,
price_type . currency_id . id , res [ ' currency_id ' ] ,
product_obj . price_get ( cr , uid , [ product_id ] ,
price_type . field ) [ product_id ] , round = False , context = context )
if price :
price_limit = price
price = price * ( 1.0 + ( res [ ' price_discount ' ] or 0.0 ) )
price = rounding ( price , res [ ' price_round ' ] )
price + = ( res [ ' price_surcharge ' ] or 0.0 )
if res [ ' price_min_margin ' ] :
price = max ( price , price_limit + res [ ' price_min_margin ' ] )
if res [ ' price_max_margin ' ] :
price = min ( price , price_limit + res [ ' price_max_margin ' ] )
break
else :
# False means no valid line found ! But we may not raise an
# exception here because it breaks the search
price = False
if price :
if ' uom ' in context :
product = products_dict [ product_id ]
uom = product . uos_id or product . uom_id
price = self . pool . get ( ' product.uom ' ) . _compute_price ( cr , uid , uom . id , price , context [ ' uom ' ] )
if results . get ( product_id ) :
results [ product_id ] [ pricelist_id ] = price
else :
results [ product_id ] = { pricelist_id : price }
2010-09-27 14:21:50 +00:00
return results
2008-07-22 15:11:28 +00:00
def price_get ( self , cr , uid , ids , prod_id , qty , partner = None , context = None ) :
2010-09-29 09:57:42 +00:00
res_multi = self . price_get_multi ( cr , uid , pricelist_ids = ids , products_by_qty_by_partner = [ ( prod_id , qty , partner ) ] , context = context )
res = res_multi [ prod_id ]
res . update ( { ' item_id ' : { ids [ - 1 ] : ids [ - 1 ] } } )
return res
def price_get_old ( self , cr , uid , ids , prod_id , qty , partner = None , context = None ) :
2008-07-22 15:11:28 +00:00
'''
context = {
' uom ' : Unit of Measure ( int ) ,
' partner ' : Partner ID ( int ) ,
' date ' : Date of the pricelist ( % Y - % m - % d ) ,
}
'''
2010-09-27 14:21:50 +00:00
price = False
item_id = 0
2008-07-22 15:11:28 +00:00
context = context or { }
currency_obj = self . pool . get ( ' res.currency ' )
product_obj = self . pool . get ( ' product.product ' )
supplierinfo_obj = self . pool . get ( ' product.supplierinfo ' )
price_type_obj = self . pool . get ( ' product.price.type ' )
2007-10-10 05:44:59 +00:00
2008-07-22 15:11:28 +00:00
if context and ( ' partner_id ' in context ) :
partner = context [ ' partner_id ' ]
context [ ' partner_id ' ] = partner
date = time . strftime ( ' % Y- % m- %d ' )
if context and ( ' date ' in context ) :
date = context [ ' date ' ]
result = { }
2010-02-23 12:06:34 +00:00
result [ ' item_id ' ] = { }
2008-07-22 15:11:28 +00:00
for id in ids :
cr . execute ( ' SELECT * ' \
' FROM product_pricelist_version ' \
2008-12-10 14:29:55 +00:00
' WHERE pricelist_id = %s AND active=True ' \
2008-07-22 15:11:28 +00:00
' AND (date_start IS NULL OR date_start <= %s ) ' \
' AND (date_end IS NULL OR date_end >= %s ) ' \
' ORDER BY id LIMIT 1 ' , ( id , date , date ) )
plversion = cr . dictfetchone ( )
2007-07-19 13:35:49 +00:00
2008-07-22 15:11:28 +00:00
if not plversion :
raise osv . except_osv ( _ ( ' Warning ! ' ) ,
_ ( ' No active version for the selected pricelist ! \n ' \
' Please create or activate one. ' ) )
2006-12-07 13:41:40 +00:00
2008-07-22 15:11:28 +00:00
cr . execute ( ' SELECT id, categ_id ' \
' FROM product_template ' \
' WHERE id = (SELECT product_tmpl_id ' \
' FROM product_product ' \
2008-12-10 14:29:55 +00:00
' WHERE id = %s ) ' , ( prod_id , ) )
2008-07-22 15:11:28 +00:00
tmpl_id , categ = cr . fetchone ( )
categ_ids = [ ]
while categ :
categ_ids . append ( str ( categ ) )
cr . execute ( ' SELECT parent_id ' \
' FROM product_category ' \
2008-12-10 14:29:55 +00:00
' WHERE id = %s ' , ( categ , ) )
2008-07-22 15:11:28 +00:00
categ = cr . fetchone ( ) [ 0 ]
if str ( categ ) in categ_ids :
raise osv . except_osv ( _ ( ' Warning ! ' ) ,
_ ( ' Could not resolve product category, ' \
' you have defined cyclic categories ' \
' of products! ' ) )
if categ_ids :
categ_where = ' (categ_id IN ( ' + ' , ' . join ( categ_ids ) + ' )) '
else :
categ_where = ' (categ_id IS NULL) '
2006-12-07 13:41:40 +00:00
2008-07-22 15:11:28 +00:00
cr . execute (
' SELECT i.*, pl.currency_id '
' FROM product_pricelist_item AS i, '
' product_pricelist_version AS v, product_pricelist AS pl '
2008-12-10 14:29:55 +00:00
' WHERE (product_tmpl_id IS NULL OR product_tmpl_id = %s ) '
' AND (product_id IS NULL OR product_id = %s ) '
2008-07-22 15:11:28 +00:00
' AND ( ' + categ_where + ' OR (categ_id IS NULL)) '
2008-12-10 14:29:55 +00:00
' AND price_version_id = %s '
' AND (min_quantity IS NULL OR min_quantity <= %s ) '
2008-07-22 15:11:28 +00:00
' AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
2009-12-23 11:14:43 +00:00
' ORDER BY sequence ' ,
2008-07-22 15:11:28 +00:00
( tmpl_id , prod_id , plversion [ ' id ' ] , qty ) )
2009-12-23 11:14:43 +00:00
res1 = cr . dictfetchall ( )
for res in res1 :
2010-02-23 12:06:34 +00:00
item_id = 0
2009-12-23 11:14:43 +00:00
if res :
if res [ ' base ' ] == - 1 :
if not res [ ' base_pricelist_id ' ] :
price = 0.0
else :
price_tmp = self . price_get ( cr , uid ,
[ res [ ' base_pricelist_id ' ] ] , prod_id ,
qty ) [ res [ ' base_pricelist_id ' ] ]
ptype_src = self . browse ( cr , uid ,
res [ ' base_pricelist_id ' ] ) . currency_id . id
price = currency_obj . compute ( cr , uid , ptype_src ,
res [ ' currency_id ' ] , price_tmp , round = False )
break
elif res [ ' base ' ] == - 2 :
where = [ ]
if partner :
2010-09-27 14:21:50 +00:00
where = [ ( ' name ' , ' = ' , partner ) ]
2009-12-23 11:14:43 +00:00
sinfo = supplierinfo_obj . search ( cr , uid ,
[ ( ' product_id ' , ' = ' , tmpl_id ) ] + where )
2008-07-22 15:11:28 +00:00
price = 0.0
2009-12-23 11:14:43 +00:00
if sinfo :
cr . execute ( ' SELECT * ' \
' FROM pricelist_partnerinfo ' \
2010-06-16 11:51:39 +00:00
' WHERE suppinfo_id IN %s ' \
2009-12-23 11:14:43 +00:00
' AND min_quantity <= %s ' \
2010-06-16 11:51:39 +00:00
' ORDER BY min_quantity DESC LIMIT 1 ' , ( tuple ( sinfo ) , qty , ) )
2009-12-23 11:14:43 +00:00
res2 = cr . dictfetchone ( )
if res2 :
price = res2 [ ' price ' ]
break
2008-07-22 15:11:28 +00:00
else :
2009-12-23 11:14:43 +00:00
price_type = price_type_obj . browse ( cr , uid , int ( res [ ' base ' ] ) )
price = currency_obj . compute ( cr , uid ,
price_type . currency_id . id , res [ ' currency_id ' ] ,
product_obj . price_get ( cr , uid , [ prod_id ] ,
2010-05-13 14:21:35 +00:00
price_type . field ) [ prod_id ] , round = False , context = context )
2006-12-07 13:41:40 +00:00
2009-12-23 11:14:43 +00:00
if price :
price_limit = price
price = price * ( 1.0 + ( res [ ' price_discount ' ] or 0.0 ) )
price = rounding ( price , res [ ' price_round ' ] )
price + = ( res [ ' price_surcharge ' ] or 0.0 )
if res [ ' price_min_margin ' ] :
price = max ( price , price_limit + res [ ' price_min_margin ' ] )
if res [ ' price_max_margin ' ] :
price = min ( price , price_limit + res [ ' price_max_margin ' ] )
2010-02-23 12:06:34 +00:00
item_id = res [ ' id ' ]
2009-12-23 11:14:43 +00:00
break
2010-02-01 08:29:39 +00:00
2008-07-22 15:11:28 +00:00
else :
2009-12-23 11:14:43 +00:00
# False means no valid line found ! But we may not raise an
# exception here because it breaks the search
price = False
2010-02-23 12:06:34 +00:00
result [ id ] = price
result [ ' item_id ' ] = { id : item_id }
2008-07-22 15:11:28 +00:00
if context and ( ' uom ' in context ) :
product = product_obj . browse ( cr , uid , prod_id )
uom = product . uos_id or product . uom_id
result [ id ] = self . pool . get ( ' product.uom ' ) . _compute_price ( cr ,
2009-11-24 12:09:06 +00:00
uid , uom . id , result [ id ] , context [ ' uom ' ] )
2010-09-27 14:21:50 +00:00
2008-07-22 15:11:28 +00:00
return result
2007-10-10 05:44:59 +00:00
2006-12-07 13:41:40 +00:00
product_pricelist ( )
2007-10-10 05:44:59 +00:00
2006-12-07 13:41:40 +00:00
class product_pricelist_version ( osv . osv ) :
2008-07-22 15:11:28 +00:00
_name = " product.pricelist.version "
_description = " Pricelist Version "
_columns = {
' pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' Price List ' ,
2010-02-04 07:12:40 +00:00
required = True , select = True , ondelete = ' cascade ' ) ,
2009-01-22 23:04:36 +00:00
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
2009-03-15 17:52:31 +00:00
' active ' : fields . boolean ( ' Active ' ,
help = " When a version is duplicated it is set to non active, so that the " \
" dates do not overlaps with original version. You should change the dates " \
" and reactivate the pricelist " ) ,
2008-07-22 15:11:28 +00:00
' items_id ' : fields . one2many ( ' product.pricelist.item ' ,
' price_version_id ' , ' Price List Items ' , required = True ) ,
2009-01-27 11:15:46 +00:00
' date_start ' : fields . date ( ' Start Date ' , help = " Starting date for this pricelist version to be valid. " ) ,
' date_end ' : fields . date ( ' End Date ' , help = " Ending date for this pricelist version to be valid. " ) ,
2009-12-23 14:11:38 +00:00
' company_id ' : fields . related ( ' pricelist_id ' , ' company_id ' , type = ' many2one ' ,
readonly = True , relation = ' res.company ' , string = ' Company ' , store = True )
2008-07-22 15:11:28 +00:00
}
_defaults = {
' active ' : lambda * a : 1 ,
}
2007-10-10 05:44:59 +00:00
2009-03-15 17:52:31 +00:00
# We desactivate duplicated pricelists, so that dates do not overlap
2010-11-19 13:48:01 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2009-03-15 17:52:31 +00:00
if not default : default = { }
default [ ' active ' ] = False
return super ( product_pricelist_version , self ) . copy ( cr , uid , id , default , context )
2010-11-19 13:48:01 +00:00
def _check_date ( self , cursor , user , ids , context = None ) :
for pricelist_version in self . browse ( cursor , user , ids , context = context ) :
2008-07-22 15:11:28 +00:00
if not pricelist_version . active :
continue
2009-03-15 17:52:31 +00:00
where = [ ]
if pricelist_version . date_start :
where . append ( " ((date_end>= ' %s ' ) or (date_end is null)) " % ( pricelist_version . date_start , ) )
if pricelist_version . date_end :
where . append ( " ((date_start<= ' %s ' ) or (date_start is null)) " % ( pricelist_version . date_end , ) )
2009-04-09 10:02:19 +00:00
2008-07-22 15:11:28 +00:00
cursor . execute ( ' SELECT id ' \
' FROM product_pricelist_version ' \
2009-03-15 17:52:31 +00:00
' WHERE ' + ' and ' . join ( where ) + ( where and ' and ' or ' ' ) +
' pricelist_id = %s ' \
2008-07-22 15:11:28 +00:00
' AND active ' \
2009-03-15 17:52:31 +00:00
' AND id <> %s ' , (
2008-07-22 15:11:28 +00:00
pricelist_version . pricelist_id . id ,
pricelist_version . id ) )
if cursor . fetchall ( ) :
return False
return True
2007-10-10 05:44:59 +00:00
2008-07-22 15:11:28 +00:00
_constraints = [
2009-04-09 10:02:19 +00:00
( _check_date , ' You cannot have 2 pricelist versions that overlap! ' ,
2008-07-22 15:11:28 +00:00
[ ' date_start ' , ' date_end ' ] )
]
2007-10-10 05:44:59 +00:00
2006-12-07 13:41:40 +00:00
product_pricelist_version ( )
class product_pricelist_item ( osv . osv ) :
2010-11-19 13:48:01 +00:00
def _price_field_get ( self , cr , uid , context = None ) :
2008-12-13 06:05:19 +00:00
pt = self . pool . get ( ' product.price.type ' )
ids = pt . search ( cr , uid , [ ] , context = context )
2008-12-08 17:08:40 +00:00
result = [ ]
2008-12-13 06:05:19 +00:00
for line in pt . browse ( cr , uid , ids , context = context ) :
result . append ( ( line . id , line . name ) )
2008-12-08 17:08:40 +00:00
result . append ( ( - 1 , _ ( ' Other Pricelist ' ) ) )
result . append ( ( - 2 , _ ( ' Partner section of the product form ' ) ) )
2008-07-22 15:11:28 +00:00
return result
2006-12-07 13:41:40 +00:00
2008-07-22 15:11:28 +00:00
_name = " product.pricelist.item "
_description = " Pricelist item "
_order = " sequence, min_quantity desc "
_defaults = {
' base ' : lambda * a : - 1 ,
' min_quantity ' : lambda * a : 0 ,
' sequence ' : lambda * a : 5 ,
' price_discount ' : lambda * a : 0 ,
}
2009-11-24 12:09:06 +00:00
2010-11-19 13:48:01 +00:00
def _check_recursion ( self , cr , uid , ids , context = None ) :
for obj_list in self . browse ( cr , uid , ids , context = context ) :
2009-11-04 09:56:30 +00:00
if obj_list . base == - 1 :
main_pricelist = obj_list . price_version_id . pricelist_id . id
other_pricelist = obj_list . base_pricelist_id . id
if main_pricelist == other_pricelist :
2009-11-24 12:09:06 +00:00
return False
2009-11-04 09:56:30 +00:00
return True
2009-11-24 12:09:06 +00:00
2008-07-22 15:11:28 +00:00
_columns = {
2008-09-22 05:56:30 +00:00
' name ' : fields . char ( ' Rule Name ' , size = 64 , help = " Explicit rule name for this pricelist line. " ) ,
2010-02-04 07:12:40 +00:00
' price_version_id ' : fields . many2one ( ' product.pricelist.version ' , ' Price List Version ' , required = True , select = True , ondelete = ' cascade ' ) ,
2008-09-22 05:56:30 +00:00
' product_tmpl_id ' : fields . many2one ( ' product.template ' , ' Product Template ' , ondelete = ' cascade ' , help = " Set a template if this rule only apply to a template of product. Keep empty for all products " ) ,
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , ondelete = ' cascade ' , help = " Set a product if this rule only apply to one product. Keep empty for all products " ) ,
' categ_id ' : fields . many2one ( ' product.category ' , ' Product Category ' , ondelete = ' cascade ' , help = " Set a category of product if this rule only apply to products of a category and his childs. Keep empty for all products " ) ,
2006-12-07 13:41:40 +00:00
2009-01-27 11:15:46 +00:00
' min_quantity ' : fields . integer ( ' Min. Quantity ' , required = True , help = " The rule only applies if the partner buys/sells more than this quantity. " ) ,
2009-12-21 13:14:12 +00:00
' sequence ' : fields . integer ( ' Sequence ' , required = True , help = " Gives the sequence order when displaying a list of pricelist items. " ) ,
2009-01-27 11:15:46 +00:00
' base ' : fields . selection ( _price_field_get , ' Based on ' , required = True , size = - 1 , help = " The mode for computing the price for this rule. " ) ,
2008-07-22 15:11:28 +00:00
' base_pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' If Other Pricelist ' ) ,
2006-12-07 13:41:40 +00:00
2008-07-22 15:11:28 +00:00
' price_surcharge ' : fields . float ( ' Price Surcharge ' ,
2010-03-06 20:52:19 +00:00
digits_compute = dp . get_precision ( ' Sale Price ' ) ) ,
2008-07-22 15:11:28 +00:00
' price_discount ' : fields . float ( ' Price Discount ' , digits = ( 16 , 4 ) ) ,
' price_round ' : fields . float ( ' Price Rounding ' ,
2010-03-06 20:52:19 +00:00
digits_compute = dp . get_precision ( ' Sale Price ' ) ,
2008-09-22 05:56:30 +00:00
help = " Sets the price so that it is a multiple of this value. \n " \
" Rounding is applied after the discount and before the surcharge. \n " \
2009-01-27 11:15:46 +00:00
" To have prices that end in 9.99, set rounding 10, surcharge -0.01 " \
2008-09-22 05:56:30 +00:00
) ,
2009-01-27 11:15:46 +00:00
' price_min_margin ' : fields . float ( ' Min. Price Margin ' ,
2010-03-06 20:52:19 +00:00
digits_compute = dp . get_precision ( ' Sale Price ' ) ) ,
2009-01-27 11:15:46 +00:00
' price_max_margin ' : fields . float ( ' Max. Price Margin ' ,
2010-03-06 20:52:19 +00:00
digits_compute = dp . get_precision ( ' Sale Price ' ) ) ,
2009-12-23 14:11:38 +00:00
' company_id ' : fields . related ( ' price_version_id ' , ' company_id ' , type = ' many2one ' ,
readonly = True , relation = ' res.company ' , string = ' Company ' , store = True )
2008-07-22 15:11:28 +00:00
}
2009-11-24 12:09:06 +00:00
2009-11-04 09:56:30 +00:00
_constraints = [
( _check_recursion , _ ( ' Error ! You cannot assign the Main Pricelist as Other Pricelist in PriceList Item! ' ) , [ ' base_pricelist_id ' ] )
]
2009-11-24 12:09:06 +00:00
2010-11-19 13:48:01 +00:00
def product_id_change ( self , cr , uid , ids , product_id , context = None ) :
2008-07-22 15:11:28 +00:00
if not product_id :
return { }
prod = self . pool . get ( ' product.product ' ) . read ( cr , uid , [ product_id ] , [ ' code ' , ' name ' ] )
if prod [ 0 ] [ ' code ' ] :
return { ' value ' : { ' name ' : prod [ 0 ] [ ' code ' ] } }
return { }
2006-12-07 13:41:40 +00:00
product_pricelist_item ( )
2008-07-23 14:41:47 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: