I have a button in a form that when clicked is supposed to update the current model mrl with data from the spray.action model. Then I do further processing but it raises the error
ValueError("Expected singleton: %s" % self) ValueError: Expected singleton: spray.action(1, 2)
#api.multi
def mrlCreateSprayRecords(self):
spray_ids = []
vals = []
spray_obj = self.env['spray.action'].search([])
print("spray_obj \n\n\n\t %s ", spray_obj)
for obj in spray_obj:
print("Spray Action Objects \n\n %s \n\t ", obj)
vals = {
'ref': obj.ref,
'farm': obj.farm.farm,
'block': obj.block.block,
'valves': obj.valves.valve,
}
print("Spray Action Data Browse , \n\n\t %s ", vals)
res = super(Mrl, self).create(vals)
res.update(vals)
print("object in mrlCreateSprayRecords \n\n\t %s", res)
return {
'name': 'Update Mrl Operations',
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mrl',
'views': [(spray_obj.id, 'form')],
'view_id': spray_obj.id,
# 'target': 'new',
'res_id': self.id,
'context': self.env.context,
}
I think you are getting the error in the row 'view_id': spray_obj.id, you must write the view id there. The spray_obj recordset has many record, so you cannot use it like that (spray_obj.id). You can also remove the view_id parameter in order to user the default view.
#api.multi
def mrlCreateSprayRecords(self):
self.ensure_one()
spray_obj = self.env['spray.action'].search([]) # recordset of all records of the model????
for obj in spray_obj:
vals = {
'ref': obj.ref,
'farm': obj.farm.farm,
'block': obj.block.block,
'valves': obj.valves.valve,
}
self.create(vals)
view_id = self.env.ref('module.xml_view_id').id
return {
'name': 'Update Mrl Operations',
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mrl',
'view_id': view_id,
'res_id': self.id,
'context': self.env.context,
}
I have added self.ensure_one() because res_id has to be only one id as well.
I have remove the res.update(vals) line because it does not make any sense to me haha
More things
Instead of print you should use the logger:
import logging
_logger = logging.getLogger(__name__)
_logger.info('Hello')
Instead the line res = super(Mrl, self).create(vals) I think you should use this one
res = self.create(vals) # if you are in the mrl model
In short you get this kind of error when you acces a field direclty of a recordSet that contains more than one record.
You performed a search on the spray.action that search returnd 2 record (1, 2)
So when you do spray_obj.id odoo will be confused what id he should return 1 or 2. And here odoo throw this error.
So dont access a field a search result, or a x2many fiels they may have more than one record inside.
#ChesuCR has improved your code and corrected it
Related
I have the below code I have the formcontrol value (its a multicheckbox list), the values is an array of true/false, [true, false, true, true, ...]. This is one of the many lists
I also have the data list - collection of objects of structure {id: number, desc: string, disabled: boolean, selected: boolean}
I need to retrieve the id matching the true by matching index, and set an observable
I have the below code
valueChanged(e: any, name: string, key: string, valuesArray: string) {
this.hasChanged = true;
from(name).pipe(
debounceTime(200),
withLatestFrom(this[name].value), // this[name] is form array, gives [true, false, false,..]
mergeMap(values => forkJoin(
of(values),
this[valuesArray].find(val => val.name === name).data
)),
mergeMap(([values, data]) => {
flatMap((val, i) => val ? data[i].id : null),
filter(id => id !== null),
map(ids => {
this.selectedFilters[key] = ids;
switch (key) {
case 'groupId':
this.curGroup.next(ids);
break;
}
});
})
);
}
I need help on the line flatmap where I want to use values, for each of the value (true/false), if val[i] is true, include data[i].id in the output i want he id array of true values [1,2,4,5,..]. I get the error
Argument of type '([values, data]: [[string, unknown], unknown]) => void' is not assignable to parameter of type '(value: [[string, unknown], unknown], index: number) => ObservableInput'.
Type 'void' is not assignable to type 'ObservableInput'.ts(2345)
Need help on how to use solve this issue. Thanks in advance.
I'm trying to return a tree view in Odoo filtered by a parameter. Some one knows how to code the variable my_context of the view?
I need to apply the filter with the field: father_competence_id
The filter is defined as:
<filter name="groupby_fathercompetence"
context="{'group_by' : 'father_competence_id'}"
string="Father competence" />
academic_record_lines = self.env['education.record']
for line in self:
academic_record_lines = academic_record_lines + line.env['education.record'].search([('n_line_id', '=', line.id)])
return {
'name': _('Academic records for {} [{}]').format(
description, self.planification_id.teacher_id.name),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'education.record',
'type': 'ir.actions.act_window',
'context': **my_context**,
'domain': [('id', 'in', academic_record_lines.ids)],
}
Please use the below code
my_context = dict(self._context or {})
my_context.update({'':})
Using my_context.update you can add filters through context.
return {
'name': _('Academic records for {} [{}]').format(
description, self.planification_id.teacher_id.name),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'education.record',
'type': 'ir.actions.act_window',
'context': my_context,
'domain': [('id', 'in', academic_record_lines.ids)],
}
If you know the filter name, which is normally set by attribute name on the search <filter> entries, you can automatically activate them by an action by providing the filter name with search_default_ in front of it and as value a truthy value like True or 1.
academic_record_lines = self.env['education.record'].search(
[('n_line_id', 'in', self.ids)])
context = dict(self.env.context or {})
context['search_default_groupby_fathercompetence'] = True
return {
# self.pla... only working with singleton!!!
'name': _('Academic records for {} [{}]').format(
description, self.planification_id.teacher_id.name),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'education.record',
'type': 'ir.actions.act_window',
'context': context,
'domain': [('id', 'in', academic_record_lines.ids)],
}
I'm new to OpenERP 7, what is the correct way to return a tree view? How can i return the data i obtained from my function?
Here's my class code:
class albaranes_fallidos(osv.osv):
_name = 'albaranes_fallidos'
_inherit = 'stock.picking'
_columns = {}
def find(self, cr, uid, ids, context=None):
stock_picking = self.pool.get('stock.picking')
exist_state = stock_picking.search(cr, uid, [('state','=','confirmed'),('origin','ilike','SO')])
###
exist_lines = stock_picking.browse(cr, uid, exist_state, context)
###
exist_IN = stock_picking.search(cr, uid, [('type','=','in'),('origin','ilike',':SO')])
for SO in exist_lines:
exist_PO = stock_picking.browse(cr, uid, exist_IN, context)
for POSO in exist_PO:
if SO.origin in POSO.origin:
_logger.info(POSO.origin)
break
You need to use a domain to specify which record to load in tree view:
return {
'type': 'ir.actions.act_window',
'name': _('Stock picking'),
'res_model': 'stock.picking',
'view_type': 'form',
'view_mode': 'tree,form',
'target': 'current',
'domain': [('id', 'in', exist_IN)]
}
In a wizzard view I have a button returning pdf report in a 'ir.action.act_url'. It works fine. Problem is that after the pdf appeared I would like the wizzard window to be closed automatically. To do this I can return close_window dict.
Separately this two 'return' work fine.
I would like to execute two actions, one after another. I found that this is possible using ir.action.server with multi attribute.
Unfortunately I couldn't find even one example.
close_window = {'type': 'ir.actions.act_window_close'}
final_report = {
'type': 'ir.actions.act_url',
'url': '/web/binary/saveas?model=ir.attachment&field=datas&
filename_field=name&id=' + str(file.id),
'target': 'self',
}
return final_report
Check the ir_actions tests that ship with Odoo, they might be able to help you in the right direction.
base/tests/test_ir_actions.py
def test_60_multi(self):
cr, uid = self.cr, self.uid
# Data: 2 server actions that will be nested
act1_id = self.ir_actions_server.create(cr, uid, {
'name': 'Subaction1',
'sequence': 1,
'model_id': self.res_partner_model_id,
'state': 'code',
'code': 'action = {"type": "ir.actions.act_window"}',
})
act2_id = self.ir_actions_server.create(cr, uid, {
'name': 'Subaction2',
'sequence': 2,
'model_id': self.res_partner_model_id,
'state': 'object_create',
'use_create': 'copy_current',
})
act3_id = self.ir_actions_server.create(cr, uid, {
'name': 'Subaction3',
'sequence': 3,
'model_id': self.res_partner_model_id,
'state': 'code',
'code': 'action = {"type": "ir.actions.act_url"}',
})
self.ir_actions_server.write(cr, uid, [self.act_id], {
'state': 'multi',
'child_ids': [(6, 0, [act1_id, act2_id, act3_id])],
})
# Do: run the action
res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
# Test: new partner created
pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value
self.assertEqual(len(pids), 1, 'ir_actions_server: TODO')
# Test: action returned
self.assertEqual(res.get('type'), 'ir.actions.act_url')
# Test loops
with self.assertRaises(except_orm):
self.ir_actions_server.write(cr, uid, [self.act_id], {
'child_ids': [(6, 0, [self.act_id])]
})
Have not done it myself, but it looks like you have to specify that it is a multi action, and specify the child_ids actions to be executed.
Also keep in mind that according to the docs (https://www.odoo.com/documentation/8.0/reference/actions.html):
multi
Executes multiple actions one after the other. Actions to execute are
defined via the child_ids m2m. If sub-actions themselves return
actions, the last one will be returned to the client as the multi's
own next action
According to #dgeorgiev I wrote further code. I managed to create server actions and individually this actions are able to return pdf file or close the window. But I couldn't combine these two return's. See below:
# first server action returning pdf
ir_actions_server = self.env['ir.actions.server']
act1_id = ir_actions_server.create({
'type': 'ir.actions.server',
'name': 'divided_package_labels',
'sequence': 1,
'model_id': self.id,
'state': 'code',
'code': 'action = {"type": "ir.actions.act_url", "url": "/web/binary/saveas?model=ir.attachment&field=datas&filename_field=name&id= %s", "target": "new"}' % str(file.id),
})
# second server action closing window
act2_id = ir_actions_server.create({
'type': 'ir.actions.server',
'name': 'Close_sale.package.wizard',
'sequence': 2,
'model_id': self.id,
'state': 'code',
'code': 'action = {"type": "ir.actions.act_window_close"}'
})
# server action for combining two previously described
act_id = ir_actions_server.create({
'type': 'ir.actions.server',
'name': 'TestAction',
'condition': 'True',
'model_id': self.id,
'state': 'multi',
# 'child_ids': [(6, 0, [act1_id.id])] # return pdf
# 'child_ids': [(6, 0, [act2_id.id])] # close window
'child_ids': [(6, 0, [act1_id.id, act2_id.id])] # close window, no pdf file
})
print act_id, act1_id, act2_id
print "act_id.child_ids", act_id.child_ids
# shows that the relations are properly made
# run
return act_id.run()
Probably there is a small mistake, but I couldn't find it.
I have the following code:
sql = "select Board_Name AS 'Board Name', COUNT(Board_Name) AS 'Count' from dbo.TABLE GROUP BY Board_Name"
result = client.execute(sql)
result.each do |row|
binfo = [ label: row['Board Name'], value: row['Count'] ]
send_event('ticketsbyboard', { items: binfo })
end
I'm trying to get all of the rows passed to the send_event as one array, instead of just one row at a time.
Try a map:
binfo = result.map do |row|
{ label: row['Board Name'], value: row['Count'] }
end
send_event('ticketsbyboard', { items: binfo })
If your result object doesn't respond directly to map, just use result.to_a.map