Use dates in pricelist version

bzr revid: ced-2f98b9105141b8373dc5cec0c48e90edb451aab3
This commit is contained in:
ced 2007-10-10 05:44:59 +00:00
parent 88dce40a88
commit a6b8fe83b7
6 changed files with 154 additions and 49 deletions

View File

@ -30,6 +30,7 @@ from osv import fields, osv
#from tools.misc import currency
from _common import rounding
import time
class price_type(osv.osv):
"""
@ -85,64 +86,102 @@ class product_pricelist(osv.osv):
'active': lambda *a: 1,
}
# context = { 'uom': Unit of Measure (Int), 'partner': Partner ID (int) }
def price_get(self, cr, uid, ids, prod_id, qty, partner=None, context={}):
if context and ('partner_id' in context):
partner = context['partner_id']
def price_get(self, cr, uid, ids, prod_id, qty, partner=None, context=None):
'''
context = {
'uom': Unit of Measure (int),
'partner': Partner ID (int),
'date': Date of the pricelist (%Y-%m-%d),
}
'''
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')
if context and ('partner_id' in context):
partner = context['partner_id']
date = time.strftime('%Y-%m-%d')
if context and ('date' in context):
date = context['date']
result = {}
for id in ids:
# XXX add date test to select the pricelist version
cr.execute('select * from product_pricelist_version where pricelist_id=%d and active=True order by id limit 1', (id,))
cr.execute('SELECT * ' \
'FROM product_pricelist_version ' \
'WHERE pricelist_id = %d AND active=True ' \
'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()
if not plversion:
raise osv.except_osv('Warning !', 'No active version for the selected pricelist !\nPlease create or activate one.')
raise osv.except_osv('Warning !',
'No active version for the selected pricelist !\n' \
'Please create or activate one.')
cr.execute('select id,categ_id from product_template where id=(select product_tmpl_id from product_product where id=%d)', (prod_id,))
tmpl_id,categ = cr.fetchone()
cr.execute('SELECT id, categ_id ' \
'FROM product_template ' \
'WHERE id = (SELECT product_tmpl_id ' \
'FROM product_product ' \
'WHERE id = %d)', (prod_id,))
tmpl_id, categ = cr.fetchone()
categ_ids = []
while categ:
categ_ids.append(str(categ))
cr.execute('select parent_id from product_category where id=%d', (categ,))
cr.execute('SELECT parent_id ' \
'FROM product_category ' \
'WHERE id = %d', (categ,))
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 !')
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)+'))'
categ_where = '(categ_id IN (' + ','.join(categ_ids) + '))'
else:
categ_where = '(categ_id is null)'
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=%d) '
'and (product_id is null or product_id=%d) '
'and ('+categ_where+' or (categ_id is null)) '
'and price_version_id=%d '
'and (min_quantity is null or min_quantity<=%f) '
'and i.price_version_id=v.id and v.pricelist_id=pl.id '
'order by sequence limit 1', (tmpl_id, prod_id, plversion['id'], qty))
'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 = %d) '
'AND (product_id IS NULL OR product_id = %d) '
'AND (' + categ_where + ' OR (categ_id IS NULL)) '
'AND price_version_id = %d '
'AND (min_quantity IS NULL OR min_quantity <= %f) '
'AND i.price_version_id = v.id AND v.pricelist_id = pl.id '
'ORDER BY sequence LIMIT 1',
(tmpl_id, prod_id, plversion['id'], qty))
res = cr.dictfetchone()
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.pool.get('product.pricelist').browse(cr, uid, res['base_pricelist_id']).currency_id.id
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)
elif res['base'] == -2:
where = []
if partner:
where = [('name', '=', partner) ]
sinfo = self.pool.get('product.supplierinfo').search(cr, uid, [('product_id', '=', prod_id)]+where)
sinfo = supplierinfo_obj.search(cr, uid,
[('product_id', '=', prod_id)] + where)
if not sinfo:
result[id] = 0
continue
cr.execute('select * from pricelist_partnerinfo where suppinfo_id in (' + ','.join(map(str, sinfo)) + ') and min_quantity<=%f order by min_quantity desc limit 1', (qty,))
cr.execute('SELECT * ' \
'FROM pricelist_partnerinfo ' \
'WHERE suppinfo_id IN (' + \
','.join(map(str, sinfo)) + ') ' \
'AND min_quantity <= %f ' \
'ORDER BY min_quantity DESC LIMIT 1', (qty,))
res = cr.dictfetchone()
if res:
result[id] = res['price']
@ -150,11 +189,11 @@ class product_pricelist(osv.osv):
result[id] = 0
continue
else:
price_type_o=self.pool.get('product.price.type').read(cr, uid, [ res['base'] ])[0]
price_type = price_type_obj.browse(cr, uid, res['base'])
price = currency_obj.compute(cr, uid,
price_type_o['currency_id'][0], res['currency_id'],
price_type.currency_id.id, res['currency_id'],
product_obj.price_get(cr, uid, [prod_id],
price_type_o['field'])[prod_id], round=False)
price_type.field)[prod_id], round=False)
price_limit = price
@ -166,32 +205,74 @@ class product_pricelist(osv.osv):
if res['price_max_margin']:
price = min(price, price_limit+res['price_max_margin'])
else:
# False means no valid line found ! But we may not raise an
# False means no valid line found ! But we may not raise an
# exception here because it breaks the search
price = False
result[id] = price
if 'uom' in context:
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,
uid, uom.id, result[id], context['uom'])
return result
product_pricelist()
class product_pricelist_version(osv.osv):
_name = "product.pricelist.version"
_description = "Pricelist Version"
_columns = {
'pricelist_id': fields.many2one('product.pricelist', 'Price List', required=True, select=True),
'pricelist_id': fields.many2one('product.pricelist', 'Price List',
required=True, select=True),
'name': fields.char('Name', size=64, required=True),
'active': fields.boolean('Active'),
'items_id': fields.one2many('product.pricelist.item', 'price_version_id', 'Price List Items', required=True),
'items_id': fields.one2many('product.pricelist.item',
'price_version_id', 'Price List Items', required=True),
'date_start': fields.date('Start Date'),
'date_end': fields.date('End Date')
'date_end': fields.date('End Date'),
}
_defaults = {
'active': lambda *a: 1,
}
def _check_date(self, cursor, user, ids):
for pricelist_version in self.browse(cursor, user, ids):
if not pricelist_version.active:
continue
cursor.execute('SELECT id ' \
'FROM product_pricelist_version ' \
'WHERE ((date_start <= %s AND %s <= date_end ' \
'AND date_end IS NOT NULL) ' \
'OR (date_end IS NULL AND date_start IS NOT NULL ' \
'AND date_start <= %s) ' \
'OR (date_start IS NULL AND date_end IS NOT NULL ' \
'AND %s <= date_end) ' \
'OR (date_start IS NULL AND date_end IS NULL) ' \
'OR (%s = \'0000-01-01\' AND date_start IS NULL) ' \
'OR (%s = \'0000-01-01\' AND date_end IS NULL) ' \
'OR (%s = \'0000-01-01\' AND %s = \'0000-01-01\')) ' \
'AND pricelist_id = %d ' \
'AND active ' \
'AND id <> %d', (pricelist_version.date_end or '0000-01-01',
pricelist_version.date_start or '0000-01-01',
pricelist_version.date_end or '0000-01-01',
pricelist_version.date_start or '0000-01-01',
pricelist_version.date_start or '0000-01-01',
pricelist_version.date_end or '0000-01-01',
pricelist_version.date_start or '0000-01-01',
pricelist_version.date_end or '0000-01-01',
pricelist_version.pricelist_id.id,
pricelist_version.id))
if cursor.fetchall():
return False
return True
_constraints = [
(_check_date, 'You can not have 2 pricelist version that overlaps!',
['date_start', 'date_end'])
]
product_pricelist_version()
class product_pricelist_item(osv.osv):

View File

@ -110,7 +110,6 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Products Price List">
<separator string="Pricelist Name" colspan="4"/>
<field name="name" select="1"/>
<field name="active" select="1"/>
<field name="type" select="1"/>
@ -121,7 +120,8 @@
<field name="active" select="2"/>
<field name="date_start" select="1"/>
<field name="date_end" select="1"/>
<field name="items_id" colspan="4" nolabel="1" widget="one2many_list"/>
<field name="items_id" colspan="4" nolabel="1"
widget="one2many_list"/>
</form>
<tree string="Pricelist Version">
<field name="name"/>

View File

@ -323,7 +323,8 @@ class purchase_order_line(osv.osv):
default.update({'state':'draft', 'move_id':False})
return super(purchase_order_line, self).copy(cr, uid, id, default, context)
def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom, partner_id):
def product_id_change(self, cr, uid, ids, pricelist, product, qty, uom,
partner_id, date_order=False):
if not pricelist:
raise osv.except_osv('No Pricelist !', 'You have to select a pricelist in the sale form !\n Please set one before choosing a product.')
if not product:
@ -337,7 +338,13 @@ class purchase_order_line(osv.osv):
prod_uom_po = prod['uom_po_id'][0]
if not uom:
uom = prod_uom_po
price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist], product, qty or 1.0, partner_id, {'uom': uom})[pricelist]
if not date_order:
date_order = time.strftime('%Y-%m-%d')
price = self.pool.get('product.pricelist').price_get(cr,uid,[pricelist],
product, qty or 1.0, partner_id, {
'uom': uom,
'date': date_order,
})[pricelist]
dt = (DateTime.now() + DateTime.RelativeDateTime(days=prod['seller_delay'] or 0.0)).strftime('%Y-%m-%d')
prod_name = self.pool.get('product.product').name_get(cr, uid, [product], context=context)[0][1]
@ -353,8 +360,10 @@ class purchase_order_line(osv.osv):
res['domain'] = domain
return res
def product_uom_change(self, cr, uid, ids, pricelist, product, qty, uom, partner_id):
res = self.product_id_change(cr, uid, ids, pricelist, product, qty, uom, partner_id)
def product_uom_change(self, cr, uid, ids, pricelist, product, qty, uom,
partner_id, date_order=False):
res = self.product_id_change(cr, uid, ids, pricelist, product, qty, uom,
partner_id, date_order=date_order)
if 'product_uom' in res['value']:
del res['value']['product_uom']
if not uom:

View File

@ -128,8 +128,11 @@
<notebook>
<page string="Order Line">
<field name="product_qty"/>
<field name="product_uom" on_change="product_uom_change(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id)"/>
<field name="product_id" colspan="4" on_change="product_id_change(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id)" context="partner_id=parent.partner_id,quantity=product_qty,pricelist=parent.pricelist_id,uom=product_uom,warehouse=parent.warehouse_id"/>
<field name="product_uom"
on_change="product_uom_change(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order)"/>
<field name="product_id" colspan="4"
on_change="product_id_change(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order)"
context="partner_id=parent.partner_id,quantity=product_qty,pricelist=parent.pricelist_id,uom=product_uom,warehouse=parent.warehouse_id"/>
<field name="name" colspan="4"/>
<field name="date_planned"/>
<field name="price_unit"/>

View File

@ -656,7 +656,7 @@ class sale_order_line(osv.osv):
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True):
lang=False, update_tax=True, date_order=False):
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
@ -675,8 +675,13 @@ class sale_order_line(osv.osv):
'You have to select a pricelist in the sale form !\n'
'Please set one before choosing a product.')
if not date_order:
date_order = time.strftime('%Y-%m-%d')
price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
product, qty or 1.0, partner_id, {'uom': uom})[pricelist]
product, qty or 1.0, partner_id, {
'uom': uom,
'date': date_order,
})[pricelist]
if price is False:
raise osv.except_osv('No valid pricelist line found !',
"Couldn't find a pricelist line matching this product and quantity.\n"

View File

@ -88,12 +88,19 @@
<form string="Sale Order Lines">
<notebook>
<page string="Order Line">
<separator string="Automatic Declaration" colspan="4"/>
<field name="product_uom_qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False)" context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom" select="1"/>
<separator string="Automatic Declaration"
colspan="4"/>
<field name="product_uom_qty"
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], False, parent.date_order)"
context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom"
select="1"/>
<field name="product_uom"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], True)" context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom" colspan="4" select="1"/>
<separator string="Manual Description" colspan="4"/>
<field name="product_id"
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, 'lang' in context and context['lang'], True, parent.date_order)"
context="partner_id=parent.partner_id,quantity=product_uom_qty,pricelist=parent.pricelist_id,shop=parent.shop_id,uom=product_uom"
colspan="4" select="1"/>
<separator string="Manual Description"
colspan="4"/>
<field name="name" colspan="4" select="2"/>
<field name="price_unit" select="2"/>
<field name="discount"/>