Fill many2many field from other many2many field - python

In product.template model, I have a one2many field(attribute_line_ids) making reference the following class:
class product_attribute_line(osv.osv):
_name = "product.attribute.line"
_rec_name = 'attribute_id'
_columns = {
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete='cascade'),
'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='restrict'),
'value_ids': fields.many2many('product.attribute.value', id1='line_id', id2='val_id', string='Product Attribute Value'),
}
On the other hand, in product.template created a many2one field making reference to a new model(comun.denominador):
'cm_id' : fields.many2one('comun.denominador','Comun denominador', select=True, ondelete='cascade')
So that when I select 'cm_id' it brings records to product.template from comun.denominador by means of on_change function.
This is my onchange_function:
def on_change_cm_id(self,cr, uid, ids,cm_id,context=None):
context=context or {}
attributes_product_template = []
value = {}
if ids:
old_note_ids = self.pool.get('product.attribute.line').search(cr, uid,[('product_tmpl_id','in',ids)])
self.pool.get('product.attribute.line').unlink(cr, uid, old_note_ids)
attribute_cm_ids = []
attribute_cm_ids = self.pool.get('attribute.comun.denominador.line').search(cr, uid, [('comun_denominador_id', '=', cm_id)])
for attribute_id in self.pool.get('attribute.comun.denominador.line').read(cr, uid, attribute_cm_ids, ['attribute_comun_denominador_id', 'value_comun_denominador_ids']):
attributes_product_template.append((0,0,{'value_ids':attribute_id['value_comun_denominador_ids'][0],'attribute_id':attribute_id['attribute_comun_denominador_id'][0]}))
value.update(attribute_line_ids=attributes_product_template)
return {'value':value}
These models store information in comun.denominador:
class product_attribute_line(osv.osv):
_name = "attribute.comun.denominador.line"
_rec_name = 'attribute_comun_denominador_id'
_columns = {
'comun_denominador_id': fields.many2one('comun.denominador', 'Comun denominador', required=True, ondelete='cascade'),
'attribute_comun_denominador_id': fields.many2one('product.attribute', 'Attribute', required=True, ondelete='restrict', readonly=True),
'value_comun_denominador_ids': fields.many2many('product.attribute.value', id1='line_id', id2='val_id', string='Product Attribute Value'),
}
class comun_denominador(osv.osv):
_name='comun.denominador'
_rec_name='comun_denominador'
_columns = {
'comun_denominador': fields.char('Común denominador', size=10),
'code': fields.char('Código clasificación', size=10),
'attribute_line_comun_denominador_ids' : fields.one2many('attribute.comun.denominador.line', 'comun_denominador_id', 'Atributos del comun denominador')
}
As you can see in my onchange_function all I want to do is to populate fields
'attribute_id'
and
'value_ids'
from 'product.attribute.line' model with the values 'attribute_comun_denominador_id' and 'value_comun_denominador_ids' belonging to 'attribute.comun.denominador.line' model.
Onchange function works great with fields many2one ('attribute_comun_denominador_id'->'attribute_id'), but in the case of many2many fields ('value_comun_denominador_ids'->'value_ids'), I get this error:
File "/home/odoo/openerp/fields.py", line 1568, in convert_to_cache
raise ValueError("Wrong value for %s: %s" % (self, value))
ValueError: Wrong value for product.attribute.line.value_ids: 1
Does anyone know how to do migration correctly between many2many fields?

def on_change_cm_id(self,cr, uid, ids,cm_id,context=None):
context=context or {}
attributes_product_template = []
value = {}
if ids:
old_note_ids = self.pool.get('product.attribute.line').search(cr, uid,[('product_tmpl_id','in',ids)])
self.pool.get('product.attribute.line').unlink(cr, uid, old_note_ids)
attribute_cm_ids = []
attribute_cm_ids = self.pool.get('attribute.comun.denominador.line').search(cr, uid, [('comun_denominador_id', '=', cm_id)])
for attribute_id in self.pool.get('attribute.comun.denominador.line').read(cr, uid, attribute_cm_ids, ['attribute_comun_denominador_id', 'value_comun_denominador_ids']):
attributes_product_template.append((0,0,{'value_ids':[(6,0,[attribute_id['value_comun_denominador_ids'][0]])],'attribute_id':attribute_id['attribute_comun_denominador_id'][0]}))
value.update(attribute_line_ids=attributes_product_template)
return {'value':value}

Related

Create new record from sale order with product order in Odoo

I want to create recordset with product in my custom class from sale order after calling an event. I will create a record in sale.order and like creating invoice, I will create record in my custom module.
What I have done is:
In my custom class:
class LoadingSlip(models.Model):
_name = 'loading.slip'
_description = 'loading information'
partner_id = fields.Char("Customer Name")
order_date = fields.Date("Order Date")
expiration_date = fields.Date("Expiration Date")
# order_line = fields.One2many('sale.order.line', 'order_id', string="Order Lines")
product_line = fields.One2many('loading.product.line', 'loading_product', string="Loading Products")
class LoadingProduct(models.Model):
_name = 'loading.product.line'
_description = "Loading Product Informations"
products_id = fields.Many2one('product.product', string='Product',
ondelete='restrict', index=True)
quantity = fields.Float(string='Quantity', default=1)
loading_product = fields.Many2one('loading.slip', string="Loading Reference", ondelete='cascade', index='True')
In sale.order
class sale_func(models.Model):
_inherit = 'sale.order'
#api.multi
def _prepare_slip(self):
test.set_trace()
self.ensure_one()
slip = {
'partner_id': self.partner_id.name,
'order_date': self.date_order,
'expiration_date': self.validity_date,
}
return slip
#api.multi
def action_slip_create(self, grouped=False, final=False):
test.set_trace() # debug point
pprint(self)
inv_obj = self.env['loading.slip']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
slips={}
pprint(slips)
slipReferences={}
test.set_trace()
for order in self:
group_key = order.id
test.set_trace()
for line in order.order_line:
if group_key not in slips:
inv_data = order._prepare_slip()
loadingslip = inv_obj.create(inv_data)
slipReferences[loadingslip] = order
slips[group_key] = loadingslip
if line.product_uom_qty > 0:
line.slip_line_create(slips[group_key].id)
if not slips:
raise UserError(_('There is no loading slip line.'))
#api.multi
def create_slip(self):
test.set_trace()
pprint(self)
sale_orders = self.env['sale.order'].browse(self._context.get('active_ids', []))
self.action_slip_create(sale_orders)
In sale.order.line
class sales_order(models.Model):
_inherit="sale.order.line"
#api.multi
def _prepare_slip_line(self):
test.set_trace()
self.ensure_one()
res={}
pprint(res)
res={
'products_id': self.product_id.id or False,
'quantity': self.product_uom_qty
}
pprint(res)
#api.multi
def slip_line_create(self, loading_product):
test.set_trace()
prdct_order = self.env['loading.product.line']
for line in self:
vals = line._prepare_slip_line()
prdct_order.create(vals)
My error is:
> /home/diwap/odoo-dev/custom-addons/sales_ext_agni/models/models.py(196)slip_line_create()
195 vals = line._prepare_slip_line()
--> 196 prdct_order.create(vals)
197
ipdb> n
TypeError: "argument of type 'NoneType' is not iterable"
I have tried update and write method instead of create in line 196 but I could not get any result it's just come up with an empty field and also no error. However when I try the real thing and i.e. write() I get this error. Is there any wrong somewhere in my code or its just an horrible thing I am doing.

Openerp how to create records from one class to another

I have these four classes named roster_time, roster_type, roster_allocation and roster_substitution and each class connect with one to many relationship except roster_substitution.
class roster_time(osv.osv):
_name="roster.time"
_description = "To create roster time slot"
_columns={
'roster_id':fields.integer('Roster ID'),
'start_time': fields.char('Start Time',required=True),
'end_time':fields.char('End Time',required=True),
'rostertype':fields.many2one('roster.type','roster','Roster Time'),
'name':fields.char('Roster Time'),
}
roster_time()
Roster Definition class
class roster_type(osv.osv):
_name="roster.type"
_description = "To create roster type for each department"
_columns={
'name': fields.char('Roster type'),
'roster':fields.one2many('roster.time','rostertype','Time Slot'),
'allocation_id':fields.many2one('roster.allocation','Roster ID'),
'roster_time':fields.many2one('roster.time','Slot'),
'roster_end':fields.related('roster.time','roster_start',type='char',string='End Time'),
'allocation_start_day':fields.date('Start Date' ),
'allocation_end_day':fields.date('End Date'),
'department_id':fields.many2one('hr.department','Department',required=True),
}
roster_time()
Roster allocation class
class roster_allocation(osv.osv):
_name="roster.allocation"
_description ="Allocate rosters on employees"
_columns={
'emp_id':fields.many2one('hr.employee','Employee',required=True),
'department_id':fields.many2one('hr.department','Department',required=True),
#'roster':fields.many2one('roster.type','roster', 'Roster ID'),
'roster_linked_ids':fields.one2many('roster.type','allocation_id','Roster Linked Ids'),
'roster_type':fields.related('roster.type','department_id', type='char', string='Roster Type'),
'roster_time':fields.char('Take the related field roster_time.name'),
'monthly allocation':fields.char('Month') ,
'roster_rest_allocation':fields.one2many('roster.rest.days','roster_id','Rest Days'),
'roster_substitute':fields.one2many('roster.substitution','allocation_id','Substitution'),
}
roster_allocation()
Roster Cancellation class
class roster_substitution(osv.osv):
_name="roster.substitution"
_description="Substituting employees "
_columns={
'allocation_id':fields.many2one('roster.allocation','Allocation'),
'employee':fields.many2one('hr.employee','Employee'),
'sub_employee':fields.many2one('hr.employee','Employee'),
'time_slot':fields.many2one('roster.time','Roster'),
'roster_day':fields.date('Day'),
'reason':fields.text('Reason'),
'department_id':fields.many2one('hr.department','Department'),
}
roster_substitution()
What I trying to do is once I cancel a allocation using roster_substitution class I want that record in with the newly allocated person in roster_allocation table using the selected date and time. How to do that
this is my attempt to do it and it's obviously not working
def allocation_substitute(self,cr,uid,ids,roster_day,context=None):
sub_day=vals.get(roster_day)
sub_time_slot=vals.get(time_slot)
allocation_obj=self.pool.get('roster.allocation')
original_employee_id = allocation_obj.browse(cr,uid, values['emp_id']).id
original_employee_roster=allocation_obj.browse(cr,uid, original_employee_id).roster_type
values={'emp_id':'employee',
'department_id':'department_id',
}
allocation_id=allocation_obj.create(cr, uid, value, context=context)
return True
The emp_id and department_id from the object roster.allocation are both many2one field. When passing value to write/create the value should be the database identifier of the record to set, in this case it's the id to hr.employeefor emp_id and hr.department for department_id.
for example:
def allocation_substitute(self,cr,uid,ids,roster_day,context=None):
sub_day=vals.get(roster_day)
sub_time_slot=vals.get(time_slot)
allocation_obj=self.pool.get('roster.allocation')
original_employee_id = allocation_obj.browse(cr,uid, values['emp_id']).id
original_employee_roster=allocation_obj.browse(cr,uid, original_employee_id).roster_type
emp_id = 1 # Search from hr.employee
department_id = 1 # Search from hr.department
values={'emp_id': emp_id,
'department_id': department_id,
}
allocation_id=allocation_obj.create(cr, uid, value, context=context)
return True

Openerp related fields in HR module hr_employee with Department, Division...etc and Location

I have these four classes in my OpenERP hr module as below
res_company --->hr_department-->hr_division-->hr_section
class company_new_registration(osv.osv):
_name = "hr.company.n.registration"
_description = "Company"
_columns = {
'name': fields.char('Company Name', size=128, required=True),
'depts': fields.one2many('hr.dept.n.registration', 'company_id', 'Dept'),
}
company_new_registration()
class dept_new_registration(osv.osv):
_name = "hr.dept.n.registration"
_description = "depts"
_columns = {
'name': fields.char('Dept Name', size=128, required=True),
'company_id': fields.many2one('res.company', 'Company Name', required=True),
'divisions': fields.one2many('hr.division.n.registration', 'dept_id', 'Division'),
'resres':fields.one2many('res.users','alias_id')
}
dept_new_registration()
class division_new_registration(osv.osv):
_name = "hr.division.n.registration"
_description = "Divisions"
_columns = {
'name': fields.char('Division Name', size=128, ),
'dept_id': fields.many2one('hr.dept.n.registration', 'Dept. Name', select=True, required=True),
'sections': fields.one2many('hr.section.n.registration', 'division_id', 'Section'),
}
division_new_registration()
class section_new_registration(osv.osv):
_name = "hr.section.n.registration"
_description = "sections"
_columns = {
'name': fields.char('Name', size=128),
'section_name': fields.char('Section Name', size=128, required=True),
'division_id': fields.many2one('hr.division.n.registration', 'Division Name', select=True, required=True),
}
section_new_registration()
all four classes in one2many relationship and all the above classes are have name field and one another field to have relationship respectively.
Also there is another class in my module which named hr_location which need to keep all above four classes references in order to create Organization structure.
my questions are:
I need to create a field which displays "Company name/ Department name/Division name/ Section name" in hr_location table when ever I create a new Section or Division or etc
I need to create four related field which stored company_id, department_id, division_id and section_id in hr_employee table when ever I select the location from above (in previous question) field.
First, you need to create into section_new_registration a computed field which concatenate the names of the whole hierarchy in the "Company name/ Department name/Division name/ Section name" you need.
Or you can override the create instead of an computed field:
def create(self, cr, uid, values, context=None):
company = self.pool.get('res.company').browse(cr, uid, values['company_id'], context=context)
dept = self.pool.get('hr.dept.n.registration').browse(cr, uid, values['department_id'], context=context)
division = self.pool.get('hr.division.n.registration').browse(cr, uid, values['division_id'], context=context)
values['name'] = company.name + '/' + dept.name + '/' + division.name + '/'+ values['section_name']
return super(hr_location, self).create(cr, uid, values, context=context)
Second, you need to create into hr_location a field such
'section_id': fields.many2one('hr.section.n.registration')
to accomplish your point (1)
Third, for your point (2) you need to create five fields as follows:
'location_id': fields.many2one('hr.location')
'section_id': fields.related('location_id', 'section_id', type='many2one', relation='hr.section.n.registration', store=True)
'division_id': fields.related('location_id', 'section_id', 'division_id', type='many2one', relation='hr.division.n.registration', store=True)
'department_id': fields.related('location_id', 'section_id', 'division_id', 'dept_id', type='many2one', relation='hr.dept.n.registration', store=True)
'company_id': fields.related('location_id', 'section_id', 'division_id', 'dept_id', 'company_id', type='many2one', relation='res.company', store=True)

how to get execute sql statement for following case in odoo?

I have asset.asset there i have added place1 many2one fields i will create some records through this form .
my requirement is that when i select any location in calendar.event at place the my next field should get only those records which are related to same location
suppose i have created at asset.asset like
1)
name: A1,
place:**karnataka/gulbarga/shahapur
**asset_catg_id:**hardware
**area_id:**hard disk
**asset_modelid_add: qqqq(predifined at other class or model with domain fielter by model_no+make)
**folio_no:**qqqqshahapur(auto populate by combaining location+assermodelid_add)
2)
name: B1,
place:**karnataka/gulbarga/jewargi,
**asset_catg_id:**software
**area_id:**os
**asset_modelid_add: zzzz(predifined at other class or model with domain fielter by model_no+make)
**folio_no:**zzzzjewargi(auto populate by combaining location+assermodelid_add)
i want in calendar.event inherited class when i select location the next field should get asset_modelid_add for that record only i.e in many2many fields like If A1 selected next field should get only karnataka/gulbarga/shahapur ,folio_num as qqqqshahapur
class asset_asset(osv.osv):
_inherit = "asset.asset"
#_name = "asset_asset"
_rec_name= "folio_num"
_columns = {
'name': fields.char('Asset Name', size=64),
'place1': fields.many2one('asset.parentlocation', 'Location'),
'asset_catg_id' : fields.many2one('asset.catg', 'Asset Catg Selection',select=True, required=True),
'area_id' : fields.many2one('asset.name', 'Asset Name Selection', domain="[('asset_catg_id', '=', asset_catg_id)]", select=True, required=True),
'assetmodelid_add' : fields.many2one('agile.portfolio1','Asset Model Code',domain="[('area_id', '=', area_id)]",),
'folio_num' : fields.char('Folio No',),
'asse_line':fields.one2many('asset.line','emp_id','Name Plate'),
'asse_line2':fields.one2many('asset.part','emp_id1','Parts'),
#'assed_modelid':fields.many2one('agile.portfolio1','Asset Model ID',select=True, required=True),
'quantity': fields.char('Quantity',size=64),
'uom': fields.char('Uinit of Measure',size=64),
'model_no' : fields.char('Model', size=64),
#'asset_id':fields.many2one('agile.portfolio','Asset ID'),
}
class asset_parentlocation(osv.osv):
_name="asset.parentlocation"
_rec_name="location_name"
_columns = {
'location_name' : fields.char('Asset Location', required=True),
'parent_location' : fields.many2one('asset.parentlocation','Parent Location'),
'nameee':fields.many2one('ir.attachment','Attachments'),}
def name_get(self, cr, uid, ids, context=None):
if context is None:
context = {}
if not ids:
return []
reads = self.read(cr, uid, ids, ['location_name','parent_location'], context=context)
res = []
for record in reads:
name = record['location_name']
if record['parent_location']:
name = record['parent_location'][1]+' / '+name
res.append((record['id'], name))
return res
**calendar_event.py**
class calendar_event(osv.osv):
_inherit = "calendar.event"
_rec_name = 'number'
_columns = {
'number' : fields.char('Meeting ID',readonly=1),
'place' : fields.many2one('asset.parentlocation','Substation Location',),
'assetmodelid_add' : fields.many2many('agile.portfolio1','Asset Model Code',),
'folio_num' : fields.many2many('asset.asset','asset_asset_rel','super_id','asset_asset_id','Folio Num',),
'inspection_name' : fields.many2many('asset1.inspection','asset1_inspection_rel','super_id','asset1_inspection_id','Inspection Type'),
}
please update answers how to do with sql or onchage both are acceptable
Lets consider a simple example. Suppose we have a many2one field to Product (name: product_id). We now want to change the content on this many2one field based on type selection box(name: type). Now, if I choose type as Service, only service type product should be visible in Product field.
To accomplish this, we have to define on change function on type selection box.
def onchange_type(self,cr,uid,ids, type,context=None):
product_obj = self.pool.get('product.product')
product_ids = product_obj.search(cr,uid, [('type','=',type)])
return {'domain':{'product_id':[('id','in',product_ids)]}}
In your case you will have to replicate above scenario.. Above case I have used in my project.
thanks,

domain filter for many2one fields in odoo?

Below code is asset inherited class . Here i will add 'place' field with 'Karn/Bang/Kengeri' and 'karn/bang/malleshwaram' for 'Karn/Bang/Kengeri' will add 'asset_catg_id' with A and B. then for 'karn/bang/malleshwaram' with Y and Z.
Now at calander inherited class . if i select 'place' with 'Karn/Bang/Kengeri' then next field 'asset_catg_id' i have to get only A and B drop down list. if again 'karn/bang/malleshwaram' then i have to get only Y,Z options . and previous selected 'asset_catg_id' values should get deleted . i have tried with domain filter option got keyvalue error
class asset_asset(osv.osv):
_inherit = "asset.asset"
#_name = "asset_asset"
_rec_name= "folio_num"
_columns = {
'name': fields.char('Asset Name', size=64),
'place': fields.many2one('asset.parentlocation', 'Location'),
'asset_catg_id' : fields.many2one('asset.catg', 'Asset Catg Selection', select=True, required=True),}
class asset_catg(osv.Model):
_name="asset.catg"
_rec_name='name1'
_description="Define Asset Catgs"
_columns={ 'name1':fields.char('Asset Catg Names',size=64,required=True),}
asset_catg()
class asset_parentlocation(osv.osv):
_name="asset.parentlocation"
_rec_name="location_name"
_columns = {
'location_name' : fields.char('Asset Location', required=True),
'parent_location' : fields.many2one('asset.parentlocation','Parent Location'),
'nameee':fields.many2one('ir.attachment','Attachments'),}
def name_get(self, cr, uid, ids, context=None):
if context is None:
context = {}
if not ids:
return []
reads = self.read(cr, uid, ids, ['location_name','parent_location'], context=context)
res = []
for record in reads:
name = record['location_name']
if record['parent_location']:
name = record['parent_location'][1]+' / '+name
res.append((record['id'], name))
return res
**Following code is calendar inherited class**
class calendar_event(osv.osv):
_inherit = "calendar.event"
_rec_name = 'number'
_columns = {
'number' : fields.char('Meeting ID',readonly=1),
#'place' : fields.many2one('stock.location','Substation Location',),
'place' : fields.many2one('asset.parentlocation','Substation Location',),
#'location' : fields.selection(STATUS_SELECTION,'Location', default='Board A'),
'asset_catg_id' : fields.many2one('asset.catg','Asset Catg Selection', domain="[('asset_catg_id', '=',place)]"),}
First your domain is wrong in a principle. Domain is what is "inside" a field, in other words in its model (for example field name or id in asset.catg model). So you should fix that one first.
If domain depends on another field, you can use onchange method to return domain (used placeholder place_id). Like this:
#api.onchange('place')
def onchange_place(self):
res = {}
if self.place:
res['domain'] = {'asset_catg_id': [('place_id', '=', self.place.id)]}
return res
P.S. This is example with new v8 api, but same principle applies to old api (you then don't nee to use decorator, also add cr, uid, ids on method and call it through your view. All of this not needed for new api). As it looks like you are still developing on old api.
Update
For old api:
def onchange_place(self,cr, uid, ids, place, context=None):
res = {}
if self.place: #on old api it will return id, instead of record
res['domain'] = {'asset_catg_id': [('place_id', '=', self.place)]}
return res
And then in your view (don't know what kind of view you are using):
<field name="place" on_change="onchange_place(place)"/>
Still you need to define some field in asset.catg so it would be used to match place field. For example:
'place_id': fields.many2one('asset.parentlocation', 'Place')
And then when you define asset category, you set which Place it should belong to. Then when you choose place calendar.event, onchange method will set domain on asset_catg_id field correctly.

Categories

Resources