I am trying to make a pop-up wizard with one selection with values from a compute function. As shown below. I am still unable to set the selection field values. Inside function _get_quotation_so I always get self.medical_quotation_id FALSE.
Is there a way to fill the selection field values? Maybe in the create function? Can anyone show me how?
class MedicalQuotationInvoiceWizard(models.Model):
_inherit = 'medical.quotation'
def compute_medical_quotation_so(self):
# import ipdb; ipdb.set_trace()
so = []
sos = self.medical_quotation_so_ids.search([('medical_quotation_id.id', '=', self.id)])
for record in sos:
so.append((record.id, record.name))
return so
#api.multi
def invoice_wizard(self):
# for record in self:
params={}
view_id=self.env['prescription.invoice.wizard']
params = {
'medical_quotation_id': self.id,
'invoice_version': self.invoice_version,
}
new = view_id.create(params)
return {
'type': "ir.actions.act_window",
'name': "Invoice Wizard",
'res_model': "prescription.invoice.wizard",
'view_type': "form",
'view_mode': "form",
'res_id': new.id,
'view_id': self.env.ref('medical_prescription.view_prescription_invoice_wizard', False).id,
'target': "new",
}
class PrescriptionInvoiceWizard(models.TransientModel):
_name = 'prescription.invoice.wizard'
def _get_prescription_invoice(self):
medical_quotation = self.env['medical.quotation']
return medical_quotation.compute_prescription_invoice()
invoice_version = fields.Selection(string="Invoice Version",
selection=lambda self: self._get_prescription_invoice())
logo = fields.Boolean("Company Logo")
paging = fields.Boolean("Paging")
medical_quotation_id = fields.Many2one(comodel_name='medical.quotation', string="Medical Quotation")
#api.model
def create(self, values):
# Override the original create function for the res.partner model
record = super(PrescriptionInvoiceWizard, self).create(values)
import ipdb; ipdb.set_trace()
medical_quotation = self.env['medical.quotation'].search([('id', '=', values['medical_quotation_id'])])
record['medical_quotation_id'] = medical_quotation
# Return the record so that the changes are applied and everything is stored.
return record
#api.depends('medical_quotation_id')
def _get_quotation_so(self):
# import ipdb; ipdb.set_trace()
medical_quotation = self.env['medical.quotation'].search([('id', '=', self.medical_quotation_id.id)]) <--- HERE self.medical_quotation_id ALWAYS FALSE
return medical_quotation.compute_medical_quotation_so()
medical_quotation_so_select = fields.Selection(string="SO",
selection=lambda self: self._get_quotation_so())
I actually solved this, but without using select field. I used many2one field then in the xml I put domain that filter using another field.
Thats it. If the python back end cannot do it. Then I guess the view front end will do it.
Related
I am making a package model in which one can make packages and use it in the sales order, my model's name is sale.package.
class Package(models.Model):
_name = 'sale.package'
_description = 'Package table'
name = fields.Char(string='Name', required=True)
width = fields.Float(string='Width')
height = fields.Float(string='Height')
length = fields.Float(string='Length')
maximum_weight = fields.Float(string='Maximum weight')
In order to use it in the sale order form, I inherited the sale.order model and added a Many2many field to the sale order which selects the previously made packages, I also created an Onchange function that updates an One2many field in a newly made page in the same sale order.
class SaleOrderPackage(models.Model):
_inherit = 'sale.order'
packs = fields.Many2many('sale.package', string='Package')
package_lines = fields.One2many('sale.package.lines', 'line_name', string='Package Lines')
#api.onchange('packs')
def _onchange_packs(self):
for rec in self:
lines = [(5, 0, 0)]
for line in self.packs:
values = {
'name_on_line': line.name,
'line_width': line.width,
'line_height': line.height,
'line_length': line.length,
'line_maximum_weight': line.maximum_weight,
}
lines.append((0, 0, values))
rec.package_lines = lines
Up to this everything is going fine, my new requirement is to add a smart button to the same sale order and upon clicking it, a tree view of the selected packages in the sale order must show up. I have added the smart button and defined a function in the python file which returns not only the selected but also all the packages made with the model.
def selected_packages(self):
print(self.packs)
return {
'name': 'Selected Packages',
'domain': [],
'view_type': 'form',
'res_model': 'sale.package',
'view_id': False,
'view_mode': 'tree,form',
'type': 'ir.actions.act_window'
}
As I am only a week into learning Odoo I am unable to figure out how to use the domain filter in this context, Please help.
Thanks in advance.
If you need to show only the selected packages, You have just to filter records using their id.
Use self.packs.ids to return the list of actual record ids corresponding to selected packages:
'domain': [('id', 'in', self.packs.ids)],
I need to override the create method in my model on odoo 10 :
in my module i have Three Models :
Asset With
validated = fields.Boolean("Is validated")
survey2_ids = fields.One2many('mymodule.survey2', 'asset_id', string='Survey2')
Survey2 with :
name = fields.Char()
asset_id = fields.Many2one('asset.asset', description='Asset')
survey1_id = fields.Many2one('mymodule.survey1', description="Survey1")
description = fields.Text(description="description")
Survey1 with :
name = fields.Char(description="Name")
ok = fields.Boolean("Is ok")
description = fields.Text()
The goal in here is when creating a new asset, and if validated = True: all records in mymodule.survey1 with ok==True should be copied in survey2_ids, i tried this function but it doesn't seem to be working:
#api.model
def create(self, vals):
survey1_ids = self.env['mymodule.survey1'].search([('ok', '=', True)])
if self.validated:
for rec in survey1_ids:
vals['survey2_ids'] = [(0, False, {'asset_id': self.id, 'survey2_id': rec.id,'name':rec.name,'description':})]
return super(asset_asset, self).create(vals)
Any help will be aappreciated
There are two problems in your code :
Create is kind of a "class method" (it is tied to the model, no to the record). So when you ask for the value of self.validated, this will always be false because self is not the record you're creating, it's the model. You should check vals.get('validated') instead. Or create the record before-hand and use it instead of self (in my example, res in the newly created record).
You're not really copying survey 1 into survey 2. You just have to create survey 2 using the data in survey 1.
The solution that I think is best :
#api.model
def create(self, vals):
res = super(asset_asset, self).create(vals)
if vals.get('validated'):
survey1_ids = self.env['mymodule.survey1'].search([('ok', '=', True)])
for s in survey1_ids:
v = {
'name': s.name,
'description': s.description,
'survey1_id': s.id,
'asset_id': res.id
}
self.env['mymodule.survey2'].create(v)
return res
Assuming that there are no errors in the logs, you are not getting what you intended to do. Once the code has executed, you are only getting 1 survey attached to the asset.
This is because inside the create function you wrote:
vals['survey2_ids'] = [(0, False, {'asset_id': self.id, 'survey2_id': rec.id,'name':rec.name,'description':})]
This will override the survey2_id in the vals each and every time in the for loop.
What you should do here is:
survey_2_list = []
for rec in survey1_ids:
survey_2_list.append((0, False, {'asset_id': self.id, 'survey2_id': rec.id,'name':rec.name,'description':rec.description}))
vals['survey2_ids'] = survey_2_list
Try the following:
#api.model
def create(self, vals):
survey_2_list = []
if self.validated:
survey1_ids = self.env['mymodule.survey1'].search([('ok', '=', True)])
if survey1_ids:
for rec in survey1_ids:
values = {
'asset_id': self.id,
'survey2_id': rec.id,
'name':rec.name,
'description':rec.description,
}
survey_2_list.append((0, False, values))
vals['survey2_ids'] = survey_2_list
return super(asset_asset, self).create(vals)
How to make functional field editable in Openerp?
When we create
'capname': fields.function(
_convert_capital, string='Display Name', type='char', store=True
),
This will be displayed has read-only and we can't able to edit the text.
How we make this field has editable?
A computed field has a function that automatically calculates it's value on some source data.
It is possible to add it the inverse operation, updating the source data based on a value manually set on it, thus making it editable.
From the documentation:
to allow setting values on a computed field, use the inverse parameter. It is the name of a function reversing the computation and setting the relevant fields:
Example code:
document = fields.Char(compute='_get_document', inverse='_set_document')
def _get_document(self):
for record in self:
with open(record.get_document_path) as f:
record.document = f.read()
def _set_document(self):
for record in self:
if not record.document: continue
with open(record.get_document_path()) as f:
f.write(record.document)
You must add a inverse function to make the field editable. This parameter is called fnct_inv in OpenERP v7. An example:
def _get_test(self, cr, uid, ids, name, args=None, context=None):
result = dict.fromkeys(ids, False)
for line in self.browse(cr, uid, ids, context=context):
if line.test:
result[line.id] = line.test
return result
def _set_test(self, cr, uid, id, field_name, field_value, args=None, context=None):
obj = self.browse(cr, uid, id)
for record in obj:
if record.test != field_value:
# The record already exists
...
cr.execute(
'UPDATE your_table '
'SET test=%s '
'WHERE id=%s', (field_value, id)
)
else:
# It is a new record
# (or the value of the field was not modified)
return True
_columns = {
'test': fields.function(
string='String for testing',
fnct=_get_test,
fnct_inv=_set_test,
type='char',
size=50,
store=True,
),
}
I am trying to create a function field which will get the current membership type of a member and store it in a new field in res.partner. However this code is not getting called whenever I am creating or editing membership of a member. But if I remove the store attribute the functional field works just as expected. Note that I am reusing the membership module of openerp and using odoo8 now. I am attaching the code, please let me know where am I going wrong. I need this method to be called atleast when I am using the store attribute. Am I using the store attribute incorrectly:
from openerp.osv import osv, fields
class partner_member(osv.Model):
'''Partner'''
_inherit = 'res.partner'
def _get_membership_type(self,cr,uid,ids,context=None):
member_line_obj = self.pool.get('membership.membership_line')
partner_list = []
for line in member_line_obj.browse(cr, uid, ids, context=context):
if line.state == 'paid':
partner_list.append(line.partner.id)
return partner_list
def _current_membership(self, cr, uid, ids, field_name= None, arg=False, context=None):
res_obj = self.pool.get('res.partner')
res_data_obj = res_obj.browse(cr, uid, ids, context=context)
res=dict()
for member in res_data_obj:
if member.member_lines:
for lines in member.member_lines:
if (lines.state == 'paid'):
res[member.id] = lines.membership_id.name_template
break
else:
res[member.id] = 'None'
else:
res[member.id] = 'None'
return res
_columns = {
'current_membership':
fields.function(_current_membership,type='char',
string='Current Membership Type',
store = {
'membership.membership_line':
(_get_membership_type, ['state'], 10)
},
help="Shows the current membership of a user"),
}
You made a mistake on the _get_membership_type() method. Indeed, you return only the list of res.partner that are in a line with state == 'paid'.
I think you must return all the partner that are in lines no matter the state of the line.
def _get_membership_type(self,cr,uid,ids,context=None):
member_line_obj = self.pool.get('membership.membership_line')
partner_list = []
for line in member_line_obj.browse(cr, uid, ids, context=context):
partner_list.append(line.partner.id)
return partner_list
If you want your function _current_membership to be a method of your class (as you did) you need to add the method=True parameter to your field definition:
_columns = {
'current_membership':
fields.function(_current_membership,type='char',
string='Current Membership Type',
store = {
'membership.membership_line':
(_get_membership_type, ['state'], 10)
},
help="Shows the current membership of a user",
method=True),
}
That should resolve your problem.
Certainly you can simply use store=True to have your field recalculated on every change in whatever field of your object.
I'm a newbie Django user, struggling with submitting form data to the database. So that I can generate dynamic forms I am using a non-ModelForm form to capture field data.
I'm commented out validation for now but I am trying to capture the POST data from the form to the database. The latest 'draft' of my views.py code is as follows - most interested in format from form_to_save = Scenario(...):
def scenario_add(request, mode_from_url):
urlmap = {
'aviation': 'Aviation',
'maritime': 'Maritime',
'international_rail': 'International Rail',
'uk_transport_outside_london': 'UK Transport (Outside London)',
'transport_in_london': 'Transport in London',
}
target_mode = urlmap[mode_from_url]
m = Mode.objects.filter(mode=target_mode)
tl = m[0].current_tl.threat_l
scenario_form = ScenarioForm(request.POST or None, current_tl=tl, mode=target_mode)
if request.method == 'POST':
#if scenario_form.is_valid():
form_to_save = Scenario(
target = Target(descriptor = scenario_form.fields['target']),
t_type = ThreatType(t_type = scenario_form.fields['t_type']),
nra_reference = NraReference(nra_code = scenario_form.fields['nra_reference']),
subt = scenario_form.fields['subt'],
ship_t = ShipType(ship_t = scenario_form.fields['ship_t']),
likelihood = scenario_form.fields['likelihood'],
impact = scenario_form.fields['impact'],
mitigation = scenario_form.fields['mitigation'],
compliance_score = scenario_form.fields['compliance_score'],
notes = scenario_form.fields['notes']
)
form_to_save.save()
# This needs to be changed to a proper redirect or taken to
# a scenario summary page (which doesn't yet exit.)
return render(request, "ram/new_scenario_redirect.html", {
'scenario_form': scenario_form,
'mode': mode_from_url,
'mode_proper': target_mode
})
else:
# if there is no completed form then user is presented with a blank
# form
return render(request, 'ram/scenario_add.html', {
'scenario_form': scenario_form,
'current_tl': tl,
'mode': mode_from_url,
'mode_proper': target_mode
})
Any advice gratefully received. Many thanks.
You've commented out the is_valid check, for some reason. You need that: as well as checking for validity, it also populates the form's cleaned_data dictionary which is what you should be getting the data from to create your object. (And don't call that object "form_to_save": it's a model instance, not a form).
if request.method == 'POST':
if scenario_form.is_valid():
scenario = Scenario(
target = Target(descriptor=scenario_form.cleaned_data['target']),
t_type = ThreatType(t_type = scenario_form.cleaned_data['t_type'])
...etc
Plus, you should move the final "return render" call out of the else block, so that it is caught when the form is not valid, to show any errors.
However, as petkostas says, you would almost certainly be better off using an actual ModelForm in the first place.
You can add custom options by overriding the init function in your form. For example:
class SomeForm(forms.Form):
department = forms.ChoiceField(widget=forms.Select, required=True)
...
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
self.fields['department'].choices = Department.objects.all().order_by('department_name).values_list('pk', 'department_name')
You can also change the queryset in the init function:
where Department is a foreign key for example
queryset = Department.objects.filter(your logic)
self.fields['department'].queryset = queryset