Odoo Error, a partner cannot follow twice the same object - python

I have receiving this odoo error when I try to duplicate a set of record. I have inherited ['mail.thread', 'ir.needaction_mixin'] in the current class. I didn't found any solution online or myself or from odoo. Still stuck here around four days.
Can anybody have an idea on this? Currently I'm using Odoo 10.
Code added is below:
#api.model
def create(self, vals):
res = super(StaffKPI, self).create(vals)
fol = {}
fol['res_model'] = 'staff.kpi'
fol['res_id'] = res.id
fol['partner_id'] = res.name_id.partner_id.id
fol_id = self.env['mail.followers'].create(fol)
self._cr.execute(
'INSERT INTO mail_followers_mail_message_subtype_rel (mail_followers_id, mail_message_subtype_id) values (%s, %s)',
(fol_id.id, 2))
self._cr.execute(
'INSERT INTO mail_followers_mail_message_subtype_rel (mail_followers_id, mail_message_subtype_id) values (%s, %s)',
(fol_id.id, 1))
subtypes = self.env['mail.message.subtype'].search([('res_model', '=', 'staff.kpi')]).ids
if subtypes:
for i in subtypes:
self._cr.execute(
'INSERT INTO mail_followers_mail_message_subtype_rel (mail_followers_id, mail_message_subtype_id) values (%s, %s)',
(fol_id.id, i))
old_name = res.name
res.write({'name': ''})
res.write({'name': old_name})
return res

You should use mail.threads built-in functions to add followers. You should always avoid the use of direct queries!
Following code will cover the follower and subtype adding (i didn't understand the name writes at the end):
#api.model
def create(self, vals):
res = super(StaffKPI, self).create(vals)
subtype_ids = self.env['mail.message.subtype'].search(
[('res_model', '=', 'staff.kpi')]).ids
res.message_subscribe(
partner_ids=[res.name_id.partner_id.id],
subtype_ids=subtype_ids)
# other logic
return res

you can use this code:
class Followers(models.Model):
_inherit = 'mail.followers'
#api.model
def create(self, vals):
if 'res_model' in vals and 'res_id' in vals and 'partner_id' in vals:
dups = self.env['mail.followers'].search([('res_model', '=',vals.get('res_model')),
('res_id', '=', vals.get('res_id')),
('partner_id', '=', vals.get('partner_id'))])
if len(dups):
for p in dups:
p.unlink()
return super(Followers, self).create(vals)

This error is because an SQL_constraint
('mail_followers_res_partner_res_model_id_uniq', 'unique(res_model,res_id,partner_id)', 'Error, a partner cannot follow twice the same object.'), ...
Located in /addons/mail/models/mail_followers.py, when you create an object the current user added automatically as follower twice in this models ['mail.followers'], so the sql_constraint will be : Unique('your_model', id_of_record_you_want_to_create, current_user) twice.
Solution : you can use option .with_context(mail_create_nosubscribe=True) and this means do not add automatically the current user as followers.
Exemple :
self.env['helpdesk.ticket'].with_context(mail_create_nosubscribe=True).create({
'name' : 'ticket_name',
'partner_id' : 22,
'team_id' : 2,
})

Related

record does not exist or has been deleted.\\n(record: account.move.line(5398,), user: 7) in odoo while updating

I'm getting record does not exist or has been deleted.\n(record: account.move.line(5398,), user: 7) error while updating data to odoo. Following is my code can anyone help to solve this problem.
import xmlrpc.client
endpoint_url = "/api/account.move/"
obj = get_object_or_404(OrderItem, order__id=order_id)
invoice_date = obj.order.created_on
name = obj.product.varient_name
price = obj.total
quantity = obj.quantity
payment_source = obj.order.payment_method
payment_reference = obj.order.order_number
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
ids = models.execute_kw(db, uid, password, 'account.move', 'search_read', [[['source_document', '=', payment_reference]]], {'fields': ['partner_id', 'id']})
invoice_id = ids[0]['id']
partner_id_ = ids[0]['partner_id'][0]
headers = {
"access-token":tokens,
"Content-type":"application/jsonp",
"Cookie":session_id
}
api_invoice_line_id = [(1, invoice_id,{'name':name, 'price_unit':price, 'quantity':quantity})]
data = {
"partner_id":partner_id_,
"invoice_date":str(invoice_date),
"move_type":"out_invoice",
"__api__invoice_line_ids":str(api_invoice_line_id),
"payment_source":payment_source,
"source_document": payment_reference,
"rider":rider_name,
"ref":""
}
datas_ = json.dumps(data, indent=4)
req = requests.put(url+endpoint_url+str(invoice_id), headers=headers, data=datas_)
if req.status_code == 200:
status = "Update Successful"
else:
status = str(req.text)
return status
It looks like your code is failing because of the tuple you give to insert/update data in __api__invoice_line_ids.
I suppose it's some account.move.line Many2many or One2many field.
I see you are using the command 1 with invoice_id (an account.move id) and some data in a dict.
The problem here is that you are then trying to add that in the field pointing to account.move.line. So your ID 5398 is the account.move id, not an account.move.line id.
Not sure what your goal is to achieve here. If it's to push/update some account.move records with new data, change your __api__invoice_line_ids to point to account.move.
If your goal is to push/update some account.move.line records, then you better loop on the line_ids of your invoice_id :)
If I wasn't clear on something or you have any other question don't hesitate asking !

Add computed field to custom filter as stored field in ODOO

customer_count = fields.Char(string='Customer Count', compute='cust_count')
class ResBuilding(models.Model):
_name = "res.partner.building"
_description = "Customer BUilding"
_order = "id desc"
region_id = fields.Many2one('res.state.city', string='Region', required=True, ondelete='cascade')
city_id = fields.Many2one('city.covered.area', string='Area', required=True, ondelete='cascade')
name = fields.Char(string='Name', required=True, translate=True, copy=False)
image = fields.Binary(string="Building image")
latitude = fields.Char(string='Latitude')
customer_count = fields.Char(string='Customer Count', compute='cust_count', store=True)
longitude = fields.Char(string='Longitude')
active = fields.Boolean(string='Active', default=True, track_visibility='onchange')
partner_ids = fields.One2many('res.partner', 'building_id', string='Customer List', readonly=True)
#api.multi
#api.depends('partner_ids')
def cust_count(self):
for record in self:
count = self.env['res.partner'].search_count([('building_id', '=', record.id)])
record.customer_count = count
#api.multi
def name_get(self):
result = []
for route in self:
name = route.city_id.name + '-' + route.name
result.append((route.id, name))
return result
#api.multi
def write(self, vals):
res = super(ResBuilding, self).write(vals)
print(vals, self.id)
if vals.get('city_id'):
customers = self.env['res.partner'].search([('building_id', '=', self.id)])
for c in customers:
c.living_area = vals.get('city_id')
return res
#api.multi
#api.depends('latitude', 'longitude')
def on_change_location(self):
for li in self:
if li.latitude and li.longitude:
self.env.cr.execute("""update res_partner set location_latitude=""" + str(li.latitude) + """,
location_longitude=""" + str(li.longitude) + """where building_id=""" + str(
li.id))
return True
#api.multi
def write(self, vals):
res = super(ResBuilding, self).write(vals)
self.on_change_region_id()
return res
#api.multi
#api.depends('region_id')
def on_change_region_id(self):
for li in self:
if li.region_id:
self.env.cr.execute(
"""update res_partner set city_id=""" + str(li.region_id.id) + """where building_id=""" + str(
li.id))
return True
I want find the customer count in a specific building based on building id. and want The coustomer_count field to be added to the add custom filter
by this code ,i am getting count correctly . But the field customer_count does not appear in custom filter
when i add store=True, the field is coming in custom filter but the count is coming as 0.
Your code is not correct, even with storing the field.
customer_count = fields.Char(
string='Customer Count', compute='cust_count', store=True)
#api.multi
#api.depends()
def cust_count(self):
for record in self:
count = self.env['res.partner'].search_count([('building_id', '=', record.id)])
record.customer_count = count
Always use for each loops in compute methods, because in case of multi relational fields using your building model or just by presenting this computed field in a list of your building model will lead to a multi recordset behind self.
But that's not all. There should be a possibility to trigger the recomputation of the field and if easy to do using depends. Right now i don't see any easy possibility, because i don't know all your relations and workflows. Without storing the field you probably don't need that, but it would work there too.
So what to do to trigger a recomputation? Just work up from the other site of the relation: res.partner. Override it's write, create and unlink method to trigger the recomputation "manually".
class ResPartner(models.Model):
_inherit = "res.partner"
#api.multi
def write(self, values):
old_buildings = self.mapped('building_id')
res = super(ResPartner, self).write(values)
if 'building_id' in values:
new_buildings = self.mapped('building_id')
trigger_buildings = old_buildins | new_buildings
trigger_buildings.cust_count()
return res
#api.model
def create(self, values):
partner = super(ResPartner, self).create(values)
partner.building_id.cust_count()
return partner
#api.multi
def unlink(self):
buildings = self.mapped('building_id')
res = super(ResPartner, self).unlink()
buildings.cust_count()
return res
Another way is to use a one2many field on your building model in relation to res.partner and fill depends with it, like depends('partner_ids'). But in my experience one2many fields in such and lot of other situations tend to lead to bad performance.

Get the sequence with existing field in odoo 10

I need to get the order number related with its service order. Each service order has many bench orders. E.g.: If the service order number is 223 the bench orders related to that are 223-1, 223-2, 223-3... if SO number is 553, bench order numbers must be 553-1, 553-2, 553-3, etc.
I tried it several ways and I failed to do it. Please help me. I used Odoo sequence to do that, but it did not give the output as I want. Here is my code: (E.g.: 223 means work authorization number).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
#api.model
def create(self, vals):
sequence = self.env['ir.sequence'].next_by_code('so.benchorder') or '/'
str_sequence = str(sequence)
query = """SELECT so_work_authorization FROM my_depots_so WHERE id=%d """ % (so_p_id)
self.env.cr.execute(query)
result = self.env.cr.fetchall()
result_number = json.dumps(result, ensure_ascii=False)
strip_number = result_number.strip('\' \" [] ')
work_auth_no = str(strip_number)
work_auth_no += "-"
work_auth_no += str_sequence
Ok, I think you are looking for something like this (I added a field to your tiq_so_parts model since you have to store the subsequence somewhere -where were you storing the 223-1, 223-2, 223-3... values?
I created the field part_sequence to store these values-).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
part_sequence = fields.Char(string='Part Sequence')
#api.model
def create(self, vals):
so_part = super(SO_Parts, self).create(vals)
so_p_id = so_part.so_p_id
main_sequence = so_p_id.so_work_authorization
part_sequence = len(so_p_id.so_parts_ids)
so_part.write({
'part_sequence': str(main_sequence) + '-' + str(part_sequence),
})
return so_part

Override metho odoo 10 isn't working

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)

Open ERP- Functional field not getting called from code

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.

Categories