Many2one field with our own function in openerp - python

I need to create many2one field.but it should need to filter data as per my logic in function.It should be selectbox also.then how to implement this in OpenERP ver 7 ?
i tried with below code.But its not give a list, which i need. It just load all value from the model.And I need the first value of the select box should be get selected by default.
def _sel_proj(self, cr, uid,context=None):
cr.execute("""SELECT project.id,account.name FROM project_project project
LEFT JOIN account_analytic_account account ON account.id = project.analytic_account_id
LEFT JOIN project_user_rel rel ON rel.project_id = project.id
WHERE (account.user_id = %s or rel.uid = %s) GROUP BY project.id,account.name"""%(uid, uid))
return [(r[0],r[1]) for r in cr.fetchall()]
_name = 'mat.mgmt'
_columns = {'project_id':fields.many2one('project.project','Project',selection=_sel_proj,select=True,required=True),}

You need to set project_id is many2one and remove selection attribute from field definition. You can make it selection from xml by using widget="selection" attribute on that field.
To get one value in default, you need to make default function for that, add your logic over there and return its first value by using result[0]. Call this function from _defaults in py like this:
def _get_project(self, cr, uid, context=None):
#ADD YOUR LOGIC
return result[0]
'project_id': _get_project
And to show the limited records as per your logic, If possible, you can convert it into domain and add the domain on project_id field from xml like this
domain="[('analytic_account_id.user_id','=',uid)]"

You Can use
'project_id': fields.selection(_get_project, 'Select Supplier'),

Related

How to do left outer join with PeeWee and no ForeignKey?

Using PeeWee on top of SQLite, I am trying to do a left outer join between two tables that do not have a ForeignKey relation defined. I can get the data if the right table an entry that matches the left table, but if there is no match, the columns in the right table do not make it into the returned models.
class BaseModel(Model):
class Meta:
database = db
class Location(BaseModel):
location_key = CharField(primary_key=True)
lat = FloatField(null = False)
lon = FloatField(null = False)
class Household(BaseModel):
name = CharField(null=True)
location_id = CharField(null=True)
I am trying to do something like:
for h in Household.select(Household,Location).join(Location, on=(Household.location_id == Location.location_key), join_type=JOIN.LEFT_OUTER):
print(type(h), h, h.location, h.location.lat)
This works if Household.location_id matches something in Location, but if Household.location_id is None (null), then I get an AttributeError: 'Household' object has no attribute 'location'
I would have expected location to be present, but have a valid of None.
How can I check for the existence of location before using it? I am trying to avoid using ForeignKey, there are a lot of mismatches between Household.location_id and Location.location_key and PeeWee really gets angry about that...
I think I understand what you're trying to do after re-reading. What I'd suggest is to use Peewee's "on" keyword argument in the join, which can patch the related Location (if it exists) onto a different attr than "location":
query = (HouseHold
.select(HouseHold, Location)
.join(Location, on=(HouseHold.location_id == Location.location_key),
attr='location_obj', join_type=JOIN.LEFT_OUTER))
Then you can check the "location_obj" to retrieve the related object.
for house in query:
# if there was a match, get the location obj or None.
location_obj = getattr(house, 'location_obj', None)
# the location_id is still present.
print(house.location_id, location_obj)
Found my own answer. Implement __getattr__(self) in the Household model, and return None if the name is 'location'. __getattr__(self) is only called if there is no property with that name.

Auto fill of two many2one fields

In hr.holidays model for employee_id field onchange function is there but I removed that onchange function from 'employee_id' field.The main aim of that function is Auto filling of 'department_id' field of same model when the change of 'employee_id' field.
problem:
My requirement is the below code is existing in odoo v7 but i need in odoo v8.
I tried in different ways but I didn't get any result so please help me.
def onchange_employee(self, cr, uid, ids, employee_id):
result = {'value': {'department_id': False}}
if employee_id:
employee = self.pool.get('hr.employee').browse(cr, uid, employee_id)
result['value'] = {'department_id': employee.department_id.id}
return result
My odoo V8 code:
I am getting object of 'hr.employee' but I am unable to fill that object in 'department_id' field because of it is many2one field.Below is my code.
#api.onchange('employee_id')
#api.constrains('employee_id')
def joining_date(self):
if self.employee_id:
self.department_id =''
depart_obj = self.env['hr.employee'].search([('name', '=' , self.employee_id.name)])
if depart_obj:
for departments in depart_obj:
depart_new_obj = self.env['hr.employee'].browse([departments.id])
for tax in depart_new_obj.department_id:
self.department_id = [tax.id]
Why are you searching and browsing object if you have already object of self.employee_id
just set
self.department_id = self.employee_id.department_id.id
At finally I got the answer removing of [ ] .""self.department_id = tax.id""

Filling Many2many field (odoo 8)

What I've done:
I have a module with
myfield = fields.Many2one('res.partner', string="Graduate", domain=[('is_graduated', '=', True)])
Then I have another class with
_inherit = 'res.partner'
is_graduated = fields.Boolean("Graduated before?", default=False)
graduations = fields.Many2many('my_module.courses', string="Graduation courses")
What I get:
The myfield works good, but the graduations field is empty. If you edit user 1 profile you can add entries to graduation field using Add item, but I need it to be filled automaticaly.
What I expect:
I expect that every record where myfield is set to lets say user 1, will be visible in field graduations when you open user 1 profile. When I create record and set myfield value to lets say user 1, that record must to be visible in user 1 profile in the field graduations. How to achieve that?
user_rel_ids = fields.Many2many(comodel_name='course',
relation='user_course_rel',
column1='user_id',
column2='course_id')
Or
user_rel_id = fields.Many2many('course')
For Filling Data (for add new relation)
user_rel_id = [(4,course_id)]
According to http://odoo4u.blogspot.com/2014/10/orm-methods.html, It says:
A full list of options is in the documentation for the class.
This same thing will apply for one2many
For a many2many and one2many field, a list of tuples is
expected. Here is the list of the tuple that is accepted, with the
corresponding semantics:
(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)
You need to use an onchange method for myfield, then inside it you need to fill the graduations field, something like this:
#api.onchange('myfield'):
def _onchange_myfield(self):
#fill graduations field here...
...
_inherit = 'crm.phonecall'
alarm_ids = fields.Many2many('calendar.alarm',string="Reminders")
set the alarm_ids of calendar.event model in create method of crm phonecall...
alarm_ids = [(6,0,self.alarm_ids.ids)]
_inherit = 'calendar.event'
alarm_ids = fields.Many2many('calendar.alarm',string="Reminders")
You can achieve like these.
For example:
#api.one
#api.depends(
#here you may define your depend field name
)
def _set_graduations(self):
#here comes your logic which will collect ids
#and than return it with self.field_name like
self.graduations = [list_of_ids]
graduations = fields.Many2many('my_module.courses', string='Payments',
compute='_set_graduations')
If you don't want to use #api.depends than you may use #api.multi. For reference you may check out account module with account_invoice.py file.

How to compute a databasefield with the field-id

Model:
db.define_table('orders',
Field('customer_id', db.customer)
Field('order_id', 'string')
)
I want to get a special order_id like XY-150012 where XY is part of the customer name, 15 is the year and 12 the id the actual record-id of orders. I tried in the model:
db.orders.order_id.compute = lambda r: "%s-%s00%s" % (db.customer(r['customer_id']).short, str(request.now.year)[2:], r['id'])
The id is never recognized, the computation ends up as None. If I remove r['id'] from the compute-line it works.
EDIT:
After adding an extra field field('running_number', 'integer') to the model I can access this fields content.
Is there a easy way to set this fields default=db.orders.id?
SOLUTION:
With Anthony´s Input, and reading about recursive selects I came up with this solution:
db.define_table('orders',
Field('customer_id', db.customer),
Field('order_id', 'string', default = None))
def get_order_id(id, short):
y = str(request.now.year)[2:]
return '%s-%s00%s' % (short, y, id)
def set_id_after_insert(fields,id):
fields.update(id=id)
def set_order_id_after_update(s,f):
row = s.select().first()
if row['order_id'] == None:
s.update_naive(order_id=get_order_id(row['id'], row['customer_id'].short)
else:
return
db.orders._after_insert.append(lambda f,id: set_id_after_insert(f,id))
db.orders._after_update.append(lambda s,f: set_order_id_after_update(s,f))
The problem is that the record ID is not known until after the record has been inserted in the database, as the id field is an auto-incrementing integer field whose value is generated by the database, not by web2py.
One option would be to define an _after_insert callback that updates the order_id field after the insert:
def order_after_insert(fields, id):
fields.update(id=id)
db(db.order.id == id).update(order_id=db.order.order_id.compute(fields))
db.order._after_insert.append(order_after_insert)
You might also want to create an _after_update callback, but in that case, be sure to use the update_naive argument in both callbacks when defining the Set (see above link for details).
Depending on how the order_id is used, another option might be a virtual field.

Onchange field not working OpenERP

I'm trying to show a res.partner field, which is called phone into the treeview of a sale.order.
But it is not showing anything, just the name of the field without data. This is my code on sale.order
phone : fields.char('Telefono del Cliente'),
Onchange function for this field:
def onchange_phone(self, cr, uid, ids, phone, context=None):
res = {}
if phone:
obj = self.pool.get('res.partner')
browse(cr, uid, phone)
res['phone'] = obj.phone
return {'value' : res}
On res.partner the field is also called phone which is obviously the client's phone, i need to show it on the sale.order treeview, this is the code on my sale_view.xml:
<field name="phone" on_change="onchange_phone(phone)"/>
Any ideas?
Thanks in advance.
As a suggestion, If you want phone number of partner, than you should not create on_change of phone field. You can get phone number in 2 ways.
First way and best way, In sale.order, onchange_partner_id() method is their, you need to override that method and update vals with phone number of partner.
And Second way and long way, You may override create() method and write() method of sale.order.
create() method trick:
in create() method, you can take partner id from the context. For example vals.get('partner_id')
write() method trick:
in write() method, you have id of created record so you need to simply browse that record and write phone number of partner.
As Odedra suggested, you should do this like so (this is taken from sale.py file):
def onchange_partner_id(self, cr, uid, ids, part, context=None):
if not part:
return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False, 'payment_term': False, 'fiscal_position': False}}
part = self.pool.get('res.partner').browse(cr, uid, part, context=context)
addr = self.pool.get('res.partner').address_get(cr, uid, [part.id], ['delivery', 'invoice', 'contact'])
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
payment_term = part.property_payment_term and part.property_payment_term.id or False
fiscal_position = part.property_account_position and part.property_account_position.id or False
dedicated_salesman = part.user_id and part.user_id.id or uid
phone = part.phone or False
val = {
'partner_invoice_id': addr['invoice'],
'partner_shipping_id': addr['delivery'],
'payment_term': payment_term,
'fiscal_position': fiscal_position,
'user_id': dedicated_salesman,
'phone': phone,
}
if pricelist:
val['pricelist_id'] = pricelist
return {'value': val}
Note that you should not do that on base module, but instead create your own module and inherit it to sale.order model. What is more, onchange will not work on tree view (like you suggested), but you can easily show it on the tree - you have to first put it on your form with the onchange provided, then modify tree view to show phone number.

Categories

Resources