Hello. I'm trying to mod an open source app called TinyERP and inherit
from a parent object, and in essence change how _column is defined. I
found sample code of:
class custom_product( osv.osv):
__inherits__ = "product.produc t"
__name__ = "product.produc t"
_columns = {
'color' : fields.many2one ('color','Color '),
'size': fields.many2one ('size','Size') ,
}
custom_product( )
This doesn't work. It does seem to override it, however, it seems to
replace the function. How can I essentially redefine the _columns var?
Thanks, Graeme
The main class looks like this:
from osv import fields
from osv import osv
from osv import orm
#----------------------------------------------------------
# UOM
#----------------------------------------------------------
class product_uom_cat eg(osv.osv):
_name = 'product.uom.ca teg'
_description = 'Product uom categ'
_columns = {
'name': fields.char('Na me', size=64, required=True),
}
product_uom_cat eg()
class product_uom(osv .osv):
_name = 'product.uom'
_description = 'Product Unit of Measure'
_columns = {
'name': fields.char('Na me', size=64, required=True),
'category_id': fields.many2one ('product.uom.c ateg', 'UOM Category',
required=True, ondelete='casca de'),
'factor': fields.float('F actor', required=True),
'rounding': fields.integer( 'Rounding Precision', required=True),
'active': fields.boolean( 'Active')
}
_defaults = {
'factor': lambda x,y,z: 1.0,
'active': lambda x,y,z: 1,
'rounding': lambda x,y,z: 2,
}
def _compute_qty(se lf, cr, uid, uom_id, qty):
if not uom_id or not qty:
return qty
f = self.read(cr, uid, [uom_id], ['factor','round ing'])[0]
return int(qty / f['factor'])
def _compute_price( self, cr, uid, uom_id, qty):
if not uom_id or not qty:
return qty
f = self.read(cr, uid, [uom_id], ['factor','round ing'])[0]
return round(qty * f['factor'], f['rounding'])
product_uom()
#----------------------------------------------------------
# Categories
#----------------------------------------------------------
class product_categor y(osv.osv):
_name = "product.catego ry"
_description = "Product Category"
_columns = {
'name': fields.char('Na me', size=64, required=True),
'parent_id': fields.many2one ('product.categ ory','Parent Category'),
'child_id': fields.one2many ('product.categ ory', 'parent_id',
string='Childs Categories')
}
def child_get(self, cr, uid, ids):
return [ids]
product_categor y()
#----------------------------------------------------------
# Products
#----------------------------------------------------------
class product_templat e(osv.osv):
_name = "product.templa te"
_description = "Product Template"
_columns = {
'name': fields.char('Na me', size=64, required=True, translate=True) ,
'description': fields.text('De scription', translate=True) ,
'description_pu rchase': fields.text('Pu rchase Description',
translate=True) ,
'description_sa le': fields.text('Sa le Description', translate=True) ,
'name_ids': fields.one2many ('product.templ ate.name', 'template_id',
'Names for Partners'),
'type': fields.selectio n([('product','Sto ckable
Product'),('ser vice','Service' )], 'Product Type', required=True),
'supply_method' :
fields.selectio n([('produce','Pro duce'),('buy',' Buy')], 'Supply
method', required=True),
'seller_id': fields.many2one ('res.partner', 'Default Supplier'),
'seller_delay': fields.float('S upplier lead time'),
'sale_delay': fields.float('P rocurement lead time'),
'seller_ids': fields.many2man y('res.partner' ,
'product_produc t_supplier', 'product_id','p artner_id','Alt ernative
Suppliers'),
'manufacturer' : fields.char('Ma nufacturer', size=64),
'manufacturer_p name' : fields.char('Ma nufacturer product name',
size=64),
'manufacturer_p ref' : fields.char('Ma nufacturer product code',
size=64),
'procure_method ': fields.selectio n([('make_to_stock ','Make to
Stock'),('make_ to_order','Make to Order')], 'Procure Method',
required=True),
'rental': fields.boolean( 'Rentable product'),
'categ_id': fields.many2one ('product.categ ory','Category' ,
required=True),
'list_price': fields.float('L ist Price'),
'volume': fields.float('V olume'),
'weight': fields.float('W eight'),
'cost_method': fields.selectio n([('standard','St andard Price'),
('pmp','PMP (Not implemented!)')], 'Costing Method', required=True),
'standard_price ': fields.float('S tandard Price', required=True),
'limit_price': fields.float('L imit Price'),
'warranty': fields.float('W arranty (months)'),
'sale_ok': fields.boolean( 'Can be sold'),
'purchase_ok': fields.boolean( 'Can be Purchased'),
'taxes_id': fields.many2man y('account.tax' , 'product_taxes_ rel',
'prod_id', 'tax_id', 'Product Taxes'),
'uom_id': fields.many2one ('product.uom', 'Default UOM',
required=True),
'uom_po_id': fields.many2one ('product.uom', 'Purchase UOM',
required=True),
'state': fields.selectio n([('draft', 'In
Development'),( 'sellable','Sel lable'),('end', 'End of
lifecycle'),('o bsolete','Obsol ete')], 'State'),
}
_defaults = {
'type': lambda x,y,z: 'product',
'list_price': lambda x,y,z: 1,
'cost_method': lambda x,y,z: 'standard',
'supply_method' : lambda x,y,z: 'buy',
'standard_price ': lambda x,y,z: 1,
'limit_price': lambda x,y,z: 1,
'sale_ok': lambda x,y,z: 1,
'sale_delay': lambda x,y,z: 7,
'purchase_ok': lambda x,y,z: 1,
'procure_method ': lambda x,y,z: 'make_to_stock' ,
'specific_bom': lambda x,y,z: False,
'specific_routi ng': lambda x,y,z: False,
}
# TODO: redefine name_get & name_search for product.templat e.name
def name_get(self, cr, user, ids, context={}):
if 'partner_id' in context:
pass
return orm.orm.name_ge t(self, cr, user, ids, context)
product_templat e()
class product_templat e_name(osv.osv) :
_name = "product.templa te.name"
_description = "Product Template"
_columns = {
'name': fields.char('Pr oduct Name', size=64, required=True),
'code': fields.char('Pr oduct Code', size=32),
'partner_id': fields.many2one ('res.partner', 'Partner',
ondelete='casca de'),
'template_id': fields.many2one ('product.templ ate', 'Product
Template', ondelete='casca de'),
}
product_templat e_name()
class product_product (osv.osv):
def _product_price( self, cr, uid, ids, name, arg, context={}):
res = {}
quantity = context.get('qu antity', 1)
pricelist = context.get('pr icelist', False)
if pricelist:
for id in ids:
price =
self.pool.get(' product.priceli st').price_get( cr,uid,[pricelist], id,
quantity, 'list')[pricelist]
res[id] = price
for id in ids:
res.setdefault( id, 0.0)
if 'uom' in context:
for id in ids:
res[id] = self.pool.get(' product.uom')._ compute_price(c r, uid,
context['uom'], res[id])
return res
def _product_virtua l_available(sel f, cr, uid, ids, name, arg,
context={}):
res = {}
if ('shop' in context) and context['shop']:
cr.execute('sel ect warehouse_id from sale_shop where id=%d',
(int(context['shop']),))
res = cr.fetchone()
if res:
context['warehouse'] = res[0]
if context.get('wa rehouse',False) :
cr.execute('sel ect lot_stock_id from stock_warehouse where id=%d',
(int(context['warehouse']),))
res = cr.fetchone()
context['location'] = res[0]
if context.get('lo cation',False):
res = self.pool.get(' stock.location' )._product_virt ual_get(cr, uid,
context['location'], ids)
for id in ids:
res.setdefault( id, 0)
if 'uom' in context:
for id in ids:
res[id] = self.pool.get(' product.uom')._ compute_qty(cr, uid,
context['uom'], res[id])
return res
def _product_qty_av ailable(self, cr, uid, ids, name, arg, context={}):
res = {}
if 'shop' in context:
cr.execute('sel ect warehouse_id from sale_shop where id=%d',
(int(context['shop']),))
res = cr.fetchone() or {}
if res:
context['warehouse'] = res[0]
if context.get('wa rehouse',False) :
cr.execute('sel ect lot_stock_id from stock_warehouse where id=%d',
(int(context['warehouse']),))
res = cr.fetchone() or {}
if res:
context['location'] = res[0]
if context.get('lo cation',False):
res = self.pool.get(' stock.location' )._product_get( cr, uid,
context['location'], ids) or {}
for id in ids:
res.setdefault( id, 0)
if 'uom' in context:
for id in ids:
res[id] = self.pool.get(' product.uom')._ compute_qty(cr, uid,
context['uom'], res[id])
return res
def _product_lst_pr ice(self, cr, uid, ids, name, arg, context={}):
res = {}
for p in self.browse(cr, uid, ids):
res[p.id] = p.list_price
for id in ids:
res.setdefault( id, 0)
if 'uom' in context:
for id in ids:
res[id] = self.pool.get(' product.uom')._ compute_price(c r, uid,
context['uom'], res[id])
return res
def _get_partner_co de_name(self, cr, uid, ids, product_id,
partner_id):
product = self.browse(cr, uid, [product_id])[0]
for name in product.name_id s:
if name.partner_id .id == partner_id:
return {'code' : name.code, 'name' : name.name}
return {'code' : product.default _code, 'name' : product.name}
def _product_code(s elf, cr, uid, ids, name, arg, context={}):
res = {}
for p in self.browse(cr, uid, ids):
res[p.id] = self._get_partn er_code_name(cr , uid, [], p.id,
context.get('pa rtner_id', None))['code']
return res
def _product_partne r_ref(self, cr, uid, ids, name, arg, context={}):
res = {}
for p in self.browse(cr, uid, ids):
res[p.id] = self._get_partn er_code_name(cr , uid, [], p.id,
context.get('pa rtner_id', None))['name']
return res
_defaults = {
'active': lambda x,y,z: 1
}
_name = "product.produc t"
_description = "Product"
_table = "product_produc t"
_inherits = {'product.templ ate': 'product_tmpl_i d'}
_columns = {
'qty_available' : fields.function (_product_qty_a vailable, method=True,
type='integer', string='Real Stock'),
'virtual_availa ble': fields.function (_product_virtu al_available,
method=True, type='integer', string='Virtual Stock'),
'price': fields.function (_product_price , method=True, type='float',
string='Custome r Price'),
'lst_price' : fields.function (_product_lst_p rice, method=True,
type='float', string='List price'),
'code': fields.function (_product_code, method=True, type='char',
string='Code'),
'partner_ref' : fields.function (_product_partn er_ref, method=True,
type='char', string='Custome r ref'),
'default_code' : fields.char('Co de', size=64),
'active': fields.boolean( 'Active'),
'variants': fields.char('Va riants', size=64),
'list_price_mar gin': fields.float('L ist Price Margin'),
'list_price_ext ra': fields.float('L ist Price Extra'),
'standard_price _margin': fields.float('S tandard Price Margin'),
'standard_price _extra': fields.float('S tandard Price Extra'),
'limit_price_ma rgin': fields.float('L imit Price Margin'),
'limit_price_ex tra': fields.float('L imit Price Extra'),
'product_tmpl_i d': fields.many2one ('product.templ ate', 'Product
Template', required=True),
}
def on_order(self, cr, uid, ids, orderline, quantity):
pass
def name_get(self, cr, user, ids, context={}):
if not len(ids):
return []
def _name_get(d):
name = self._product_p artner_ref(cr, user, [d['id']], '', '',
context)[d['id']]
code = self._product_c ode(cr, user, [d['id']], '', '',
context)[d['id']]
if code:
name = '[%s] %s' % (code,name)
if d['variants']:
name = name + ' - %s' % (d['variants'],)
return (d['id'], name)
result = map(_name_get, self.read(cr, user, ids, ['variants']))
return result
def name_search(sel f, cr, user, name, args=[], operator='ilike ',
context={}):
ids = self.search(cr, user, [('name',operato r,name)]+ args)
ids += self.search(cr, user, [('default_code' ,'=',name)]+ args)
return self.name_get(c r, user, ids)
def price_get(self, cr, uid, ids, ptype='list'):
result = self.read(cr, uid, ids)
result2 = {}
for res in result:
result2[res['id']] =
(res[ptype+'_price']*(1.0+(res[ptype+'_price_m argin'] or
0.0)))+(res[ptype+'_price_e xtra'] or 0.0)
return result2
product_product ()
def rounding(f, r):
if not r:
return f
return round(f / r) * r
#----------------------------------------------------------
# Price lists
#----------------------------------------------------------
class product_priceli st(osv.osv):
_name = "product.pricel ist"
_description = "Pricelist"
_columns = {
'name': fields.char('Na me',size=64, required=True),
'active': fields.boolean( 'Active'),
'version_id': fields.one2many ('product.price list.version',
'pricelist_id', 'Pricelist Versions')
}
_defaults = {
'active': lambda x,y,z: 1,
}
def price_get(self, cr, uid, ids, prod_id, qty, type='list'):
result = {}
# TODO FIXME
for id in ids:
cr.execute('sel ect * from product_priceli st_version where
pricelist_id=%d and active=True order by id limit 1', (id,))
plversion = cr.dictfetchone ()
if not plversion:
raise 'pricelist', 'No active version for this pricelist !\nPlease
create or active one.'
cr.execute('sel ect id,categ_id from product_templat e 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.appen d(str(categ))
cr.execute('sel ect parent_id from product_categor y where id=%d',
(categ,))
categ = cr.fetchone()[0]
if categ_ids:
categ_where = '(categ_id in ('+','.join(cat eg_ids)+'))'
else:
categ_where = '(categ_id is null)'
cr.execute('sel ect * from product_priceli st_item where
(product_tmpl_i d is null or product_tmpl_id =%d) and '+categ_where+' and
price_version_i d=%d and (min_quantity is null or min_quantity<=% d)
order by priority limit 1', (tmpl_id, plversion['id'], qty))
res = cr.dictfetchone ()
if res:
if res['base_pricelist _id'] and res['base']=='pricelist':
price = self.price_get( cr, uid, [res['base_pricelist _id']],
prod_id, qty, type)[res['base_pricelist _id']]
price_limit = self.price_get( cr, uid, [res['base_pricelist _id']],
prod_id, qty, 'limit')[res['base_pricelist _id']]
else:
price = self.pool.get(' product.product ').price_get(cr , uid,
[prod_id], type)[prod_id]
price_limit = self.pool.get(' product.product ').price_get(cr , uid,
[prod_id], 'limit')[prod_id]
price = price * (1.0-(res[type+'_price_di scount'] or 0.0))
price=rounding( price, res[type+'_price_ro und'])
price += (res[type+'_price_su rcharge'] or 0.0)
if res[type+'_price_mi n_margin']:
price = max(price, price_limit+res[type+'_price_mi n_margin'])
if res[type+'_price_ma x_margin']:
price = min(price, price_limit+res[type+'_price_ma x_margin'])
else:
price=False
result[id] = price
return result
product_priceli st()
class product_priceli st_version(osv. osv):
_name = "product.pricel ist.version"
_description = "Pricelist Version"
_columns = {
'pricelist_id': fields.many2one ('product.price list', 'Price List',
required=True),
'name': fields.char('Na me', size=64, required=True),
'active': fields.boolean( 'Active'),
'items_id': fields.one2many ('product.price list.item',
'price_version_ id', 'Price List Items', required=True),
'date_start': fields.date('St art Date'),
'date_end': fields.date('En d Date')
}
_defaults = {
'active': lambda x,y,z: 1,
}
product_priceli st_version()
class product_priceli st_item(osv.osv ):
_name = "product.pricel ist.item"
_description = "Pricelist item"
_order = "priority"
_defaults = {
'list_price_bas e': lambda x,y,z: 'list',
'standard_price _base': lambda x,y,z: 'standard',
'limit_price_ba se': lambda x,y,z: 'limit',
'min_quantity': lambda x,y,z: 1,
'priority': lambda x,y,z: 5,
}
_columns = {
'name': fields.char('Na me', size=64, required=True),
'price_version_ id': fields.many2one ('product.price list.version',
'Price List Version', required=True),
'product_tmpl_i d': fields.many2one ('product.templ ate', 'Product
Template'),
'categ_id': fields.many2one ('product.categ ory', 'Product Category'),
'min_quantity': fields.integer( 'Min. Quantity', required=True),
'priority': fields.integer( 'Priority', required=True),
'base':
fields.selectio n((('product',' Product'),('pri celist','Pricel ist')),
'Based on', required=True),
'base_pricelist _id': fields.many2one ('product.price list', 'Base Price
List'),
'list_price_bas e':
fields.selectio n((('list','Lis t'),('standard' ,'Standard'),(' limit','Limit') ),'List
Price Base', required=True),
'list_price_sur charge': fields.float('L ist Price Surcharge'),
'list_price_dis count': fields.float('L ist Price Discount'),
'list_price_rou nd': fields.float('L ist Price Rounding'),
'list_price_min _margin': fields.float('L ist Price Min. Margin'),
'list_price_max _margin': fields.float('L ist Price Max. Margin'),
'standard_price _base':
fields.selectio n((('list','Lis t'),('standard' ,'Standard'),(' limit','Limit') ),'Standard
Price Base', required=True),
'standard_price _surcharge': fields.float('S tandard Price Surcharge'),
'standard_price _discount': fields.float('S tandard Price Discount'),
'standard_price _round': fields.float('S tandard Price Rounding'),
'standard_price _min_margin': fields.float('S tandard Price Min.
Margin'),
'standard_price _max_margin': fields.float('S tandard Price Max.
Margin'),
'limit_price_ba se':
fields.selectio n((('list','Lis t'),('standard' ,'Standard'),(' limit','Limit') ),'Limit
Price Base', required=True),
'limit_price_su rcharge': fields.float('L imit Price Surcharge'),
'limit_price_di scount': fields.float('L imit Price Discount'),
'limit_price_ro und': fields.float('L imit Price Rounding'),
'limit_price_mi n_margin': fields.float('L imit Price Min. Margin'),
'limit_price_ma x_margin': fields.float('L imit Price Max. Margin'),
}
product_priceli st_item()