diff --git a/addons/product/pricelist.py b/addons/product/pricelist.py
index 132640787b7..e5dac1e1e30 100644
--- a/addons/product/pricelist.py
+++ b/addons/product/pricelist.py
@@ -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):
diff --git a/addons/product/pricelist_view.xml b/addons/product/pricelist_view.xml
index 8c0748082b5..33de84d7dae 100644
--- a/addons/product/pricelist_view.xml
+++ b/addons/product/pricelist_view.xml
@@ -110,7 +110,6 @@
form
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index 93b4fa08862..a9f252a090d 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -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:
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 834a96dbe69..87ef3f0a2fc 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -128,8 +128,11 @@
-
-
+
+
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 5d23726bc2d..f09ac6811b7 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -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"
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index 6393662224b..517afae76dd 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -88,12 +88,19 @@