I have this:
class events_places(osv.osv):
"""Places for events"""
_name = 'oevents.places'
_columns = {
'name': fields.char('Name',size=35, help='Place\'s name', required = True),
'description': fields.char('Description',size=50, help='Place\'s description'),
'street': fields.char('Street',size=35, help='Place\'s street', required = True),
'number': fields.integer('Local number', help='Place\'s local number', required = True),
'zip': fields.char('Zip Code', size=5, help='Place\'s Zip code', required = True),
'city': fields.char('City',size=20, help='Place\'s city', required = True),
'country': fields.many2one('res.country', 'Country', help='Place\'s country'),
'state': fields.many2one('res.country.state','State', help='Place\'s state'),
'inWinter': fields.boolean('Active in winter', store = True, help='Place\'s province'),
}
_defaults = {
'inWinter' : True,
}
class events_events(osv.osv):
"""Client's contacts"""
_name = 'oevents.events'
_columns = {
'name': fields.char('Name',size=20, help='Event\'s name', required = True),
'place': fields.many2one('oevents.places','Place', help='Event\'s location', required = True),
'artist': fields.many2one('oevents.artists','Artist', help='Artist\'s performing in the event.', required = True),
'client': fields.many2one('res.partner','Client', help='Event\'s clients.', required = True),
'date': fields.date('Date', help='Event\'s date.', required = True),
'type': fields.selection([('children','Children\'s'),('private','Private'),('concert','Concert')],'Event type', help='Type of event this artist can do'),
}
_defaults = {
'type' : 'private'
}
When I want to create an event, there's a place related field. The event has a date, but it shouldn't let me create the event in a a winter date if the related place field in the event has the field inWinter unchecked.
How can I do that? I need to create a function or constraint which gets place inWinter field and compare it with the date, but I don't know how to do it. Any suggestions?
Thanks in advance!
You can override create & write method. In those methods just check whether "inWinter" is True or False.
def create() method will be called when new record will be created.
def create(self, cr, uid, vals, context=None):
if vals.get('place'):
event_brw = self.pool.get('oevents.places').browse(cr, uid, vals.get('place'), context=context)
#if inWinter is True
if event_brw.inWinter:
raise osv.except_osv('Error ! ', 'You can not create an event in winter.')
return super(oevents_events, self).create(cr, uid, vals, context)
def write() method will be called when record will be modified.
def write(self, cr, uid, ids, vals, context=None):
if vals.get('place'):
event_brw = self.pool.get('oevents.places').browse(cr, uid, vals.get('place'), context=context)
#if inWinter is True
if event_brw.inWinter:
raise osv.except_osv('Error ! ', 'You can not create an event in winter.')
return super(oevents_events, self).write(cr, uid, ids, vals, context)
you have to write an on_change function on 'date' field, where you raise an error if given date is in winter months and isWinter is false.
Of course, yo have to define range date for iswinter an put on_change in field definition in your xml view.
you should use constraints. grep addons folder for _constraints and _sql_contraints and you'll find a lot of examples.
Go for _constraints= , Is not at all good idea to call create and write.
Related
I'm trying to add values in my one2many field onchange.
I tried using the [(0,0, {values})] but nothing happened. Any idea on how to implement it?
custom_line_ids = fields.One2many('mrp.production', 'product_id', 'Custom Line')
#api.onchange('product_id')
def add_custom_line_ids(self):
mrp = self.env['mrp.productions'].search([])
result = []
vals = {
'sequence': self.sequence,
'name': self.name,
'product_id': self.product_id,
'date_planned_start': self.date_planned_start,
'state': self.state,
}
self.update({'custom_line_ids':[(0, 0, vals)]})
Actually you are using update method, which only update the model's value but not yet stored on database. You should use write method instead.
You need to return the value in onchange. This would work:
custom_line_ids = fields.One2many('mrp.production', 'product_id', 'Custom Line')
#api.onchange('product_id')
def add_custom_line_ids(self):
vals = {}
mrp_ids = self.env['mrp.productions'].search([])
if mrp_ids:
for mrp in mrp_ids:
vals['custom_line_ids']=[(0,0,{
'date': mrp.date,
})]
return {'value': vals}
Odoo has the Reporting part and I was wondering how (if its even possible) to send reports via mail (and create an automated action for it)?
Let's say we have to crm.phonecall.report model, how to take it's information and use it in an email template? I tried making an email template with that model and then add the same xml text as it is in the Phonecall Analysis, but that didn't work. So all the help is really appreciated.
Following code will be enough to fulfill your mentioned requirements. It calls the email template and then attached a report attachment and finally send an email.
email = email_obj.browse(cr, uid, template_id)
attachment_obj = self.pool.get('ir.attachment')
ir_actions_report = self.pool.get('ir.actions.report.xml')
matching_reports = ir_actions_report.search(
cr, uid, [('name', '=', 'Report_Name_here')])
if matching_reports:
report = ir_actions_report.browse(cr, uid, matching_reports[0])
report_service = 'report.' + report.report_name
service = netsvc.LocalService(report_service)
(result, format) = service.create(
cr, uid, mrp_ids, {'model': self._name, 'start_date': start, 'end_date': end}, context=context)
if not report.attachment:
file_name = "Production Sale Report " + datetime.strftime(datetime.now().date(), "%Y-%m-%d") + ".pdf"
attachment_id = attachment_obj.create(cr, uid,
{
'name': file_name,
'datas': result,
'datas_fname': file_name,
'type': 'binary'
}, context=context)
email_obj.write(cr, uid, template_id, {'email_from': email.email_from,
'email_to': email.email_to,
'subject': email.subject,
'body_html': email.body_html,
'email_recipients': email.email_recipients,
'attachment_ids': [(6, 0, [attachment_id])],
})
email_obj.send_mail(cr, uid, template_id, False, True, context=context)
Hope this will solve your problem. Cheers
I hope this question makes sense. My goal is to display field as defined in name_get(). I have overridden name_get() function in mrp_bom class, code attached. However, I don't know which field will get return value from the function name_get(). Any insight is greatly appreciated!
class mrp_bom(osv.osv):
_inherit = 'mrp.bom'
_name = 'mrp.bom'
_columns = {
'x_nk_default_code': fields.related('product_id', 'default_code',
type='char', relation='product.product',
string='Part Number', store=True,
readonly=True),
'x_nk_class_desc': fields.related('product_id', 'categ_id', 'name',
type='char', string='Class Description',
store=True, readonly=True),
'x_nk_item_desc': fields.related('product_tmpl_id', 'name',
type='char', relation='product.template',
string='Item Description', store=True,
readonly=True),
'categ_id': fields.related('product_id', 'categ_id', type='integer',
relation='product.product', string='Categ_ID',
store=True, readonly=True),
'x_category_code': fields.related('product_id', 'categ_id',
'x_category_code', type='char', string='Class
Description', store=True, readonly=True),
}
def name_get(self, cr, user, ids, context=None):
if context is None:
context = {}
if isinstance(ids, (int, long)):
ids = [ids]
if not len(ids):
return []
def _name_get(d):
name = d.get('name','')
code = context.get('display_default_code', True) and
d.get('x_category_code',False) or False
if code:
name = '[%s] %s' % (code,name)
return (d['id'], name)
result = []
for product_category in self.browse(cr, user, ids, context=context):
mydict = {
'id': product_category.id,
'name': product_category.name,
'x_category_code':
product_category.x_category_code,
}
result.append(_name_get(mydict))
return result
The name_get method is used to display value of a record in a many2one field. For example, in a sale order line, if you select a product, the value displayed in the sale order line for the field 'product_id' must be the result of the 'name_get' on the product.product object.
There is no special field to display the result of name_get. If you need to put the result of name_get method in a field of a record, you should create with an attribute 'compute' : http://odoo-new-api-guide-line.readthedocs.org/en/latest/fields.html#computed-fields
You can find more information here : http://odoo-new-api-guide-line.readthedocs.org/en/latest/environment.html?highlight=name_get
I hope this help you.
I need to show record from notebook project on notebook sheet , but the showed record is not according to project
My py :
class notebook_project(osv.osv):
_name = "notebook.project"
_description = "Notebook Project ID"
def onchange_project(self, cr, uid, ids, project, arg, context=None):
if project :
proj = self.pool.get('project.project').browse(cr, uid, project, context=context)
return {'value': {'name': proj.name}}
return {}
_columns = {
'name' : fields.char('Name', size=64),
'project' : fields.many2one('project.project', 'Project'),
'notebook_project_lines' : fields.one2many('notebook.project', 'notebook_project_id', 'Members Lines'),
'notebook_project_id': fields.many2one('notebook.project', 'Parent Project', ondelete='cascade', select=True),
'member' : fields.many2one('hr.employee', 'Members'),
}
notebook_project()
class notebook_sheet(osv.osv):
_name = "notebook.sheet"
_description = "Notebook Project Sheet"
def onchange_notebook_project(self, cr, uid, ids, notebook_project, context=None):
res = {}
employee_lines = []
if not notebook_project : return {}
if notebook_project :
notebook_project_obj = self.pool.get('notebook.project').browse(cr, uid, notebook_project)
for p in notebook_project_obj.notebook_project_lines:
employee_lines.append((0,0,{'notebook_sheet_lines':p.id
}))#this dict contain keys which are fields of one2many field
res['notebook_sheet_lines']=employee_lines
return res
def onchange_project(self, cr, uid, ids, project, context=None):
if project :
proj = self.pool.get('project.project').browse(cr, uid, project, context=context)
return {'value': {'name': proj.name}}
return {}
#def create(self, cr, user, vals, context={}):
#first model
# notebook_project_obj = self.pool.get('notebook.project')
#browse and get o2m fields, according to your selected project(id)
# notebook_project_lines = notebook_project_obj.browse(cr, user, ['notebook_project_id'])[0].lines
#copy first o2m model to second o2m model
# for line in notebook_project_lines :
# vals['notebook_sheet_lines'].append([0, False, {'notebook_project_lines':line.employee_id.id,}])
# return super(notebook_sheet, self).create(cr, user, vals, context)
_columns = {
'name' : fields.char('Name', size=64),
'notebook_sheet_lines' : fields.many2many('notebook.project', 'notebook_project_sheet_rel', 'notebook_project', 'notebook_project_id'),
'notebook_project': fields.many2one('notebook.project', 'Project ID',domain=[('notebook_project_id','=',False)]),
'project' : fields.many2one('project.project', 'Project'),
'member' : fields.many2one('hr.employee', 'Members'),
}
notebook_sheet()
Edited my answer , Mr. AnomA . Still not sure about many2many , please kindly check it
Do i need to change the onhange event as well ? thanks again in advance
First of all please create a link between notebook.sheet and notebook.project. Now there is no link between these 2 models. Add a many2one relation to notebook.sheet in notebook.project and then change the relation id in notebook_sheets_lines to this field.
Otherwise change the relation type of notebook_sheet_lines to many2many.
Then change the onchange_notebok_project() which will return {'value':{'notebook_sheet_lines':LIST_OF_EMPOYEEIDS}}
Also No need to add many2many in motebook_project.
Really struggling with this one:
I have inherited from stock.picking.in and have added a few columns. I then added a function field.
In the function that the function field refers to, it works if I do not use any attribute from the stock.picking.in object. The moment I use any value from the object, it starts giving 'AttributeError: ' and some attribute at random. It doesn't specify any other reasons or causes.
Code:
class stock_picking_custom(osv.osv):
_name = 'stock.picking.in'
_inherit = 'stock.picking.in'
_table = "stock_picking"
def calc_royalty(self, cr, uid, ids, field_name, arg, context=None):
if not ids: return {}
res = {}
for line in self.browse(cr, uid, ids, context=context):
res[line.id] = 0 #line.royalty_rate * line.loading_netweight
return res
_columns = {
'loading_netweight': fields.float('Net weight at loading', digits=(16,2), help="Net weight at loading (interior weight)"),
'royalty_date': fields.date('Royalty Issue date'),
'royalty_number' : fields.char('Royalty Number', size=64),
'royalty_rate' : fields.float('Royalty Rate (p. ton)', digits=(16,2)),
'royalty_amount' : fields.function(calc_royalty, type='float', digits=(16,2), string='Royalty Amount', store=True, select=True)
}
stock_picking_custom()
I have commented out the line that I want to use. The moment I put this line back in the code, it would give attribute error on royalty_date (for example) which is not even mentioned in the function.
Please guide.
EDIT: I tried the exact same code with purchase.order and it works perfectly. What is different about stock.picking.in?
Thanks
Ok, found the answer in stock module in delivery addon. So this is a framework limitation issue related to inheritance order etc.
Sharing here in case someone ends up in a similar situation.
To solve, I repeated the same fields in stock.picking and stock.picking.in. Then I called the calc function of the picking class from the picking.in class.
Code:
class stock_picking_custom(osv.osv):
_name = 'stock.picking'
_inherit = 'stock.picking'
def calc_royalty(self, cr, uid, ids, field_name, arg, context=None):
if not ids: return {}
res = {}
for line in self.browse(cr, uid, ids, context=context):
res[line.id] = line.royalty_rate * line.loading_netweight
return res
_columns = {
'loading_netweight': fields.float('Net weight at loading', digits=(16,2), help="Net weight at loading (interior weight)"),
'royalty_date': fields.date('Royalty Issue date'),
'royalty_number' : fields.char('Royalty Number', size=64),
'royalty_rate' : fields.float('Royalty Rate (p. ton)', digits=(16,2)),
'royalty_amount' : fields.function(calc_royalty, type='float', digits=(16,2), string='Royalty Amount', store=True, select=True)
}
stock_picking_custom()
class stock_picking_in_custom(osv.osv):
_name = 'stock.picking.in'
_inherit = 'stock.picking.in'
_table = "stock_picking"
def calc_royalty(self, cr, uid, ids, field_name, arg, context=None):
return self.pool.get('stock.picking').calc_royalty(cr,uid,ids,field_name,arg,context=context)
_columns = {
'loading_netweight': fields.float('Net weight at loading', digits=(16,2), help="Net weight at loading (interior weight)"),
'royalty_date': fields.date('Royalty Issue date'),
'royalty_number' : fields.char('Royalty Number', size=64),
'royalty_rate' : fields.float('Royalty Rate (p. ton)', digits=(16,2)),
'royalty_amount' : fields.function(calc_royalty, type='float', digits=(16,2), string='Royalty Amount', store=True, select=True)
}
stock_picking_in_custom()
I did not get much time to spend on it but I came to know that line is coming with stock.picking.in object and fields, you defined, are stored in stock_picking table that's why it may going to search that field with stock.picking.in, not getting and error is coming.
There may be issue with fields defined in object and table, but not sure.