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.
Related
I'm adapting a module for Odoo v9 community
It uses frozendict, but everytime I try to use a feature, it throws:
NotImplementedError: 'pop' not supported on frozendict
The code is as follows:
def fields_view_get(self, cr, uid, view_id=None, view_type=False,
context=None, toolbar=False, submenu=False):
if context is None:
context = {}
journal_obj = self.pool.get('account.journal')
user_obj = self.pool.get('res.users')
# remove the entry with key 'form_view_ref', otherwise fields_view_get
# crashes
#context=dict(context)
context.pop('form_view_ref', None)
res = super(AccountInvoiceRefund, self).\
fields_view_get(cr, uid,
view_id=view_id,
view_type=view_type,
context=context,
toolbar=toolbar, submenu=submenu)
type = context.get('type', 'out_invoice')
company_id = user_obj.browse(
cr, uid, uid, context=context).company_id.id
journal_type = (type == 'out_invoice') and 'sale_refund' or \
(type == 'out_refund') and 'sale' or \
(type == 'in_invoice') and 'purchase_refund' or \
(type == 'in_refund') and 'purchase'
for field in res['fields']:
if field == 'journal_id':
journal_select = journal_obj._name_search(cr, uid, '',
[('type', '=',
journal_type),
('company_id',
'child_of',
[company_id])],
context=context)
res['fields'][field]['selection'] = journal_select
return res
Following this I've added this code to the line:
if context is None:
context = {}
journal_obj = self.pool.get('account.journal')
user_obj = self.pool.get('res.users')
context=dict(context)
context.pop('form_view_ref', None)
res = super(AccountInvoiceRefund, self).\
Instead of:
if context is None:
context = {}
journal_obj = self.pool.get('account.journal')
user_obj = self.pool.get('res.users')
context.pop('form_view_ref', None)
res = super(AccountInvoiceRefund, self).\
As You can see I've added context=dict(context), but still get the same error.
Any ideas about this?
Thanks in advance!
Contexts are frozendict objects that you cannot directly modify. This has been implemented on version 9 from what I am aware,
If you want to modify the context in your code you have to use methods provided by Odoo's API, take a look at the definition of the method named with_context on openerp/models.py around line 5460. It is sufficiently documented and you can find many examples on the source files as to how it is used.
A quick way to get over this would be to copy the frozen dictionary to another dictionary and then pass that dictionary to the method either as an argument or if you are using the new api, use the 'with_context' method.
Here is an example:
ctx = dict(self._context)
self.with_context(ctx).write({'invoice_line': []})
As you can see in the above example the _context is copied to ctx and then with_context is used to pass the new modified context.
Please in a view form I wish to use a field as key and it must be unique for each record to use it to browse the table in the other views , how to do it
class saisirsoum(osv.osv):
_name='saisir.soum'
_columns = {
'NumOffre' : fields.char('N° Offre'), # to be defined as key !!
'organisme_s' : fields.char('Organisme'),
'des_offre' : fields.char('Designation'),
'order_line' :fields.one2many('saisir.soumission.ligne','order_id','soumission_id'),
'observation_d' : fields.text('Observation'),
}
In your case you'll make NumOffre unique like this by setting the _sql_constraints variable. where you can also define a custom message to be shown when a user tries to add a duplicate entry.
class saisirsoum(osv.osv):
_name='saisir.soum'
_sql_constraints = [
('NumOffre', 'unique(NumOffre)', 'NumOffre already exists'),
]
_columns = {
'NumOffre' : fields.char('N° Offre'), # to be defined as key !!
'organisme_s' : fields.char('Organisme'),
'des_offre' : fields.char('Designation'),
'order_line' :fields.one2many('saisir.soumission.ligne','order_id','soumission_id'),
'observation_d' : fields.text('Observation'),
}
def create(self, cr, uid, vals, context=None): # when the record is about to created
NumOffre = vals.get('NumOffre') #get NumOffre from the form
if NumOffre:
pass # you can do something with it e.g searching
return super(saisirsoum, self).create(cr, uid, vals, context=context) # finally call the create method from the super class and create the record after you're done
You can also override the other CRUD methods like write and unlink in the same manner
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,
),
}
class marcos_artwork(osv.osv):
def _check_appraisal_price(self, cr, uid, ids, context=None):
record = self.pool.get('appraisal_price')
if record<0:
return False
return True
"""artwork class"""
_name = 'marcos.artwork'
_columns = {
'name': fields.char('Artwork',size=32,required=True),
'description': fields.char('Description',size=200),
'appraisal_price': fields.integer('Appraisal price' ),
'createArtWork': fields.integer('Year of creation'),
'award': fields.boolean('Award'),
'barcode': fields.integer('Barcode'),
'commission': fields.integer('Commission',size=10),
'author_ids': fields.many2one('marcos.author', 'Author'),
'typeartwork_ids': fields.many2one('marcos.artwork_type', 'Artwork Type'),
'owner_ids': fields.many2one('marcos.owner','Owner'),
'style_ids': fields.many2one('marcos.style','Style'),
'lots_ids': fields.many2many('marcos.lots','artworks_lots_form_rel','id_artwork','id_lot','Artworks'),
}
_defaults = {
'award': lambda *a: False,
}
_sql_constraints = [
('name_uniqe', 'unique(name)', 'only equals name!'),
('barcode_uniqe', 'unique(barcode)', 'only equals barcode!')
]
_constraints = [(_check_appraisal_price, 'Error: Length must be Positive', ['appraisal_price'])]
marcos_artwork()
When I want to install the module, I get shown this error:
-cannot concatenate 'str' and 'function' object...
My function is for checking that the appraisal price is positive.
Can anybody help me?
your price checking won't work this way. the big problem here is the line
record = self.pool.get('appraisal_price')
that's not correct. self.pool.get will get you instances of your "business models" like your 'marcos.artwork' but you want some field values to check.
in this case you don't even need self.pool.get, because you're already on this model and can use self instead.
so here is the code you need (you will find so many examples in the addons):
def _check_appraisal_price(self, cr, uid, ids, context=None):
for artwork in self.browse(cr, uid, ids, context):
if artwork.appraisal_price < 0:
return False
return True
I don't know this specific framework. but I guess from the code It's some kind of "orm" style class. mapping some behavior to a db/table of some sort. Really hard to tell without the full stacktrace but I believe that the error is that your are passing the __check_appraisal_price function as reference and not the result of the function - that would be something like _check_appraisal_price(arg,arg2, etc)
I need to change the state of a invoice using it's payment method.
def _payment_type_get(self, cr, uid, ids, field_name, arg, context={}):
result = {}
invoice_obj = self.pool.get('account.move.line')
for rec in self.browse(cr, uid, ids, context):
result[rec.id] = (0, 0)
invoice_id = invoice_obj.search(cr, uid, [(
'move_id', '=', rec.move_id.id)], context=context)
if invoice_id:
inv = invoice_obj.browse(cr, uid, invoice_id[0], context)
if inv.payment_type:
result[rec.id] = (inv.payment_type.id, self.pool.get(
'payment.type').browse(cr, uid, inv.payment_type.id, context).name)
else:
result[rec.id] = (0, 0)
return result
if result != '1':
return self.write(cr, uid, ids, {'state_cheque': 'usado'})
else:
return self.write(cr, uid, ids, {'state_cheque': 'caixa'})
I need to get the payment type at the creation of the "cheque", during the invoice closing, so I can set it to Caixa, if it's a Cheque or to Usado if it is not. I don't know if all the names are correct, since I copied it from a guy here who said it would(Shame on me if I let it pass).
The Cheque, like any payment is saved at a journal, cheque is saved at an specific journal with it's name(ChequeJournal), if I can use that to create the default state, It would be better.
Every single way I tried to do it, failed. Recently I've found that the payment type is saved as a int and not as a char or string, but changing it still give no results.
I could not use a self.write , since I'm editing the account_move_line.py, OpenERP can't find what I'm trying to add the state to. So, I need to get the invoice ID in order to change that state. A new problem arises?
Once a return statement is called, the function immediately exits, so your last 4 lines aren't being executed. (Or maybe that's a formatting error?)