Use dates in pricelist version
bzr revid: ced-2f98b9105141b8373dc5cec0c48e90edb451aab3
This commit is contained in:
parent
88dce40a88
commit
a6b8fe83b7
|
@ -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):
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"/>
|
||||
|
|
Loading…
Reference in New Issue