Odoo : Value in one2many doen't change in api.depends - python

I have 3 models, here is the interesting part of each:
vote:
class vote(osv.osv)
_name = 'vote'
_columns = {
name = fields.many2one('res.partner',
'Member of enterprise',
select=True),
type = fields.interger('Type'),
}
history_line:
class history_line(osv.osv)
_name = 'history_line'
_columns = {
fieldsA = fields.integer('First field'),
fieldB = fields.integer('Second field'),
this_id = fields.many2one('res.partner', 'link to res'),
}
res_partner:
class res_partner(osv.osv)
_inherit = 'res.partner'
_columns = {
vote_partner_ids = fields.one2many('vote',
'name',
'Voted peoples',
select=True),
vote_history_ids = fields.one2many('history.line',
'this_id',
compute='compute_type',
string='History of votes'),
}
#api.multi
#api.depends('vote_partner_ids.type')
def compute_type(self):
for record in self:
if self.vote_partner_ids.type:
record.vote_history_ids = [(0, 0, {'self.vote_history_ids.fieldA': self.vote_partner_ids.type + 4,
'self.vote_history_ids.fieldB': self.vote_partner_ids.type - 2})]
Their is also a default value for a new history_line (fieldA = 1 when you don't do anything, fieldB = -1 when you don't do anything for exemple)
I can't move my compute function elsewhere because lot of stuffs are computed here.
The problem is : When I modify type in vote, a new history line will be created, but with the defaults values. I can't make the values be anything else. (even If I put directly a value, like 10)
So why are the default values choose, even if I asked them to being computed, but it still understand it has to create a new tuple?

You don't have to make the "PATH" to the fields you'd like to change, remove self.vote_history_ids. in the depends before the fields to change:
#api.multi
#api.depends('vote_partner_ids.type')
def compute_type(self):
for record in self:
if self.vote_partner_ids.type:
record.vote_history_ids = [(0, 0, {'fieldA': self.vote_partner_ids.type + 4,
'fieldB': self.vote_partner_ids.type - 2})]

Related

Update one2many form view based on onchange

I assign for each project many tasks into task view form by using many2one field related project model. Then i create one2many field into project model to retrieve tasks directly into project View form, and into the code i'm looping from all the one2many fields for all tasks and append value into the one one2many field for displaying all tasks,the project_id_for_project is many2one field inside project model used to give the abaility of when i select one project it give all the attached tasks i hope you get my idea so i created the two model like below:
class project(models.Model):
_name = 'project.project'
_description = 'project.project'
project_id_for_project = fields.Many2one('project.project' )
Project_task_aff = fields.One2many('tasks.tasks','task_aff')
#api.onchange('project_id_for_project')
def getone2manyproject(self):
for rec in self:
lines = []
for line in rec.project_id_for_project.Project_task_aff :
val = {
# 'task_aff' : line.id ,
'task_actor' : line.task_actor,
'name' : line.name,
'DATE_tsk' : line.DATE_tsk,
'Description' : line.Description,
}
lines.append((0,0, val))
rec.Project_task_aff = lines
and the task model :
class tasks(models.Model):
_name = 'tasks.tasks'
_description = 'tasks.tasks'
_inherit = ['mail.thread', 'mail.activity.mixin']
task_actor = fields.Many2one('res.users', string='Chauffeur')
task_aff = fields.Many2one('project.project')
name = fields.Char()
DATE_tsk = fields.Date()
Description = fields.Char()
project_id = fields.Many2one('project.project')
the code give update the one2many field Project_task_aff but it dont give all the taks from task module: it mean that when i go into task model view, and create 5 entries related to a project, but when the onchange methode based of project_id_for_project field didn't give the 5 stored task but append just whose are stored into the onetomany field into the project view ?
You need to apply the relational field rules to update the value.
Rules:
(0, 0, { values }) link to a new record that needs to be created with the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write values on it)
(2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well)
(3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself)
(4, ID) link to existing record with id = ID (adds a relationship)
(5) unlink all (like using (3,ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs)
rec.Project_task_aff = [(6, 0, lines)]
I think this URL help with this problem and debugging.
https://raise360.odoocommunity.net/slides/slide/how-to-update-one2many-field-from-onchange-of-field-124
Try this way.
#api.onchange('project_id_for_project')
def getone2manyproject(self):
for rec in self:
tasks = self.env['tasks.tasks'].search([('task_aff', '=', rec.id)])
rec.Project_task_aff = [(6, 0, tasks.ids)]
Edit:
What is the purpose of project_id_for_project field in project's model for child parent relationship?
May be this will help, I just retrieve the first line browse loop self, and replace the tuple (0, 0, val) with (6, 0, val) in last line
#api.onchange('project_id_for_project')
def getone2manyproject(self):
lines = []
for line in self.project_id_for_project.Project_task_aff :
val = {
# 'task_aff' : line.id ,
'task_actor' : line.task_actor.id,
'name' : line.name,
'DATE_tsk' : line.DATE_tsk,
'Description' : line.Description,
}
lines.append((6, 0, val))
self.Project_task_aff = lines

api.constrain for give condition if one of field is empty

I tried to use api.constrain in odoo. The case is, I want to give condition to odoo if user missing one field, odoo will give some warning like alert, and user have to give some input to the previous field. This is my code :
class Provinc(models.Model):
_name = 'provinsi.model'
_rec_name ='prov'
prov = fields.Char(
string='Provinsi',
)
res_partner_ids = fields.One2many(
'res.partner',
'provinsi'
city_id = fields.One2many(
'city.model',
'provinsi_id'
)
class city(models.Model):
_name = 'kota.model'
_rec_name ='city'
city = fields.Char(
string='City',
)
res_partner_city = fields.One2many(
'res.partner',
'city'
)
provinsi_id = fields.Many2one(
'provinsi.model',
string='provinsi',
)
class Master_data(models.Model):
_inherit = 'res.partner'
provinsi = fields.Many2one(
'provinsi.model',
'provinsi',
)
city = fields.Many2one(
'city.model',
'city',
)
#api.onchange('provinsi')
def show_provinsi(self):
return {'domain': {'city': [('provinsi_id', '=', self.provinsi.id)]}}
#api.constrains('provinsi')
#api.onchange('city')
def show_kota(self):
for record in self:
if record.provinsi == False:
raise ValidationError("is gonna be error")
I have tried 2 ways. First, I put the api.constrain insode class City, and it's doesn't work,second ways I tried put the api.constrain like the code inside class master, and the result remains the same.
you only need onchang not any constrains to display warning!
#api.onchange('city')
def show_kota(self):
if self.city and not self.provinsi:
raise ValidationError("is gonna be error")
now if you select value in city field and provinsi missing value then it will display error msg
guessing field "city" and "provinsi" is in 'res.partner' form view!
If you want to check a field value is empty or not, just use required ="1" like:
<field name="provinsi" required="1"/>

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.

Filter Django GenericRelation based on function on foreignkey

I want to find attributes associated to my character that fit in various categories. Eventually I want this output:
"Attributes": {
"Physical": {
"Level": 1,
"Strength": 1,
"Dexterity": 1,
"Stamina": 1
},
"Mental": {
"Level": 2,
"Intelligence": 1,
"Wits": 1,
"Resolve": 1
},
"Social": {
"Level": 3,
"Presence": 1,
"Manipulation": 1,
"Composure": 1
}
},
I have an Class/Enum(AutoNumber) with the attributes in, and a method of finding which is which:
class AttributeAbility(models.Model):
class Attributes(AutoNumber):
INTELLIGENCE = () # Mental, Power
WITS = () # Mental', 'Finesse
RESOLVE = () # Mental', 'Resistance
STRENGTH = () # Physical', 'Power
DEXTERITY = () # Physical', 'Finesse
STAMINA = () # Physical', 'Resistance
PRESENCE = () # Social', 'Power
MANIPULATION = () # Social', 'Finesse
COMPOSURE = () # Social', 'Resistance
attribute = EnumField(Attributes)
#property
def attribute_type(self):
attribute_group = lambda attribute: (
int((attribute.value - 1) / 8)) + 1 % 3
return Category(attribute_group(self.attribute))
class Category(AutoNumber):
MENTAL = ()
PHYSICAL = ()
SOCIAL = ()
I connect the AttributeAbility with my character using these classes:
class CrossCharacterMixin(models.Model):
cross_character_types = models.Q(app_label='mage', model='mage')
content_type = models.ForeignKey(ContentType, limit_choices_to=cross_character_types,
null=True, blank=True)
object_id = models.PositiveIntegerField(null=True)
content_object = GenericForeignKey('content_type', 'object_id')
class Meta:
abstract = True
class CharacterAttributeLink(Trait, CrossCharacterMixin):
MIN = 1
PRIORITY_CHOICES = (
(0, 'Unassigned'), (1, 'Primary'), (2, 'Secondary'), (3, 'Tertiary')
)
attribute = models.ForeignKey('AttributeAbility')
priority = models.PositiveSmallIntegerField(
choices=PRIORITY_CHOICES, default=0
)
def __str__(self):
return self.attribute.attribute.label
And then on the Mage I have:
attributes = GenericRelation('CharacterAttributeLink')
#property
def physical_attributes(self):
type_id = Category['PHYSICAL']
return self.attributes.filter(attribute_type=type_id)
But I'm getting the error that: Cannot resolve keyword 'attribute_type' into field. Choices are: attribute, attribute_id, content_type, content_type_id, current_value, id, maximum_value, object_id, priority
And with my function like so:
#property
def physical_attributes(self):
type_id = Category['PHYSICAL']
return self.attributes.filter(attribute__attribute_type=type_id)
I get this error: Related Field got invalid lookup: attribute_type Which makes some sense (though I've seen this in the docs: >>> Entry.objects.filter(blog_id=4)).
Adding __exact on the end, gives me this: Relation fields do not support nested lookups....at which point I'm lost. Do I need a custom manager? Do I need to move my physical_attribute function elsewhere?
I ended up creating a custom manager:
class CategoryManager(models.Manager):
'''
Class to manage instances that rely on the category enum
'''
def physical(self):
return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
if categorised_item.category == Category['PHYSICAL']]
def mental(self):
return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
if categorised_item.category == Category['MENTAL']]
def social(self):
return [categorised_item for categorised_item in super(CategoryManager, self).get_queryset().all()
if categorised_item.category == Category['SOCIAL']]
And then adding this to my AttributeAbility model:
objects = CategoryManager()
And defining this property on my character model:
#property
def social_skills(self):
return [self.skills.filter(skill=skill) for skill
in SkillAbility.objects.social()]

Categories

Resources