odoo validation error when trying to create a stock.move from onchange function - odoo

So i want to automatically create a move line (move_lines) in stock.picking from an #onchange function. Here's my function : It's just a small test. When the value of the field changed change, i take it as the id of the product (product_id) in the move line and then append that move line to the already existing list of move_lines.
NB1:move_lines is a One2many relation in stock.picking.
NB2:Declaration of product_id in stock.move :
product_id = fields.Many2one(
'product.product', 'Product',
domain=[('type', 'in', ['product', 'consu'])], index=True, required=True,
states={'done': [('readonly', True)]})
My function :
changed = fields.Integer('Changed')
#api.onchange('changed')
def _changed_onchange(self):
move_lines = []
for line in self.move_lines:
move_lines.append({'product_id': line.product_id.id or False,
'product_qty': line.product_qty or 0,
'name': line.product_id.name,
'product_uom': line.product_uom.id,
'date_planned': datetime.date.today(),
'date_expected': datetime.date.today()
})
move_lines.append({'product_id': self.changed,
'name': 'default',
'product_uom': 1,
'date_planned': datetime.date.today(),
'date_expected': datetime.date.today()
})
return {'value': {'move_lines': move_lines}}
If i created the move lines using the view then saved, everything works fine but when i change the value of the field so that a new move line is inserted by the function, the save doesn't work and i keep getting the error:
Odoo Server Error - Validation Error
The operation cannot be completed, probably due to the following:
- deletion: you may be trying to delete a record while other records still reference it
- creation/update: a mandatory field is not correctly set
[object with reference: product_id - product.id]
What is the problem ?

To append line to move_lines, You can use the following syntax:
#api.onchange('changed')
def _changed_onchange(self):
values = {'product_id': self.changed,
'name': 'default',
'product_uom': 1,
'date_planned': datetime.date.today(),
'date_expected': datetime.date.today(),
'location_id': 1,
'location_dest_id': 1
}
self.move_lines |= self.move_lines.create(values)
To achieve it using your above logic you can try x2many values filling but I recommend you to use Set operations and you can find an example at Lunching wizards

Related

Odoo 14 - account.payment the invoice_ids is removed but what is it replaced with?

Till Odoo 12, while creating a payment using API calls for invoices, we had to populate the invoice_ids field on the account.payment module and it would automatically mark the corresponding invoices PAID once the payment is validated.
I understand there is no functionality loss, however, I don't know what is this functionality replaced with.
I tried using invoice_line_ids and the invoice still doesn't get marked as PAID. There is only 1 move_id and even if I try that the invoice still doesn't get marked as PAID.
any thoughts?
Edit: This is the json that I am trying to send to Odoo to register a payment against an invoice. but the response is :
"The register payment wizard should only be called on account.move or account.move.line records."
I created a separate content after passing args in the json but still the response remained the same.
{
"jsonrpc":"2.0",
"method":"call",
"params":{
"service": "object",
"method": "execute",
"args":[
"{{databaseName}}",
{{userId}},
"{{password}}",
"account.payment.register",
"create",
{
"can_edit_wizard":true,
"can_group_payments":false,
"payment_type":"inbound",
"partner_type":"customer",
"source_amount":5.48,
"source_amount_currency":5.48,
"source_currency_id":2,
"partner_id":505449,
"country_code":"US",
"journal_id":230,
"other_journal_id":false,
"show_other_journal":false,
"payment_method_id":7,
"partner_bank_id":false,
"group_payment":true,
"amount":5.48,
"currency_id":2,
"payment_date":"2022-02-04",
"communication":"Test Create Invoice 32",
"payment_difference_handling":"open",
"writeoff_account_id":false,
"writeoff_label":"Write-Off",
"active_model":"account.move",
"active_id":364660,
"active_ids":[
364660
]
}
]
}
}
Account payment wizard uses line_ids field which is supposed to be passed through the context using the active_ids key (Odoo will retrieve the account move lines using the active ids)
The active_model should be passed through the context, if the active model is different from account.move or account.move.line Odoo will raise the following error:
The register payment wizard should only be called on account.move or account.move.line records.
The following example will use the same logic used in Register Payment button to create and register invoice payment:
vals = {}
payment_register_id = models.execute_kw(db, uid, password, 'account.payment.register', 'create', [vals], {'context': {'active_model': 'account.move', 'active_ids': invoice_ids}})
models.execute_kw(db, uid, password, 'account.payment.register', 'action_create_payments', [[payment_register_id]])
The following values are the default values passed to the create method when we create a payment manually (Using the register payment button on a customer invoice form):
{'can_group_payments': False, 'payment_type': 'inbound', 'partner_type': 'customer', 'source_amount': 365125, 'source_amount_currency': 365125, 'source_currency_id': 2, 'company_id': 1, 'partner_id': 10, 'country_code': 'US', 'journal_id': 7, 'payment_method_id': 1, 'payment_token_id': False, 'partner_bank_id': False, 'group_payment': True, 'amount': 365125, 'currency_id': 2, 'payment_date': '2022-02-04', 'communication': 'INV/2021/12/0001', 'payment_difference_handling': 'open', 'writeoff_account_id': False, 'can_edit_wizard': True, 'writeoff_label': 'Write-Off'}
Edit
You can call the execute_kw method and pass context in kwargs
{'jsonrpc': '2.0',
'method': 'call',
'params': {
'service': 'object',
'method': 'execute_kw',
'args': ('{{databaseName}}',
{{userId}},
'{{password}}',
'account.payment.register',
'create',
[{'journal_id': 7, ...}],
{'context': {'active_model': 'account.move', 'active_ids': [23]}}
)
},
'id': 843350301
}
The following code is based on the JSON-RPC Library documentation example
import json
import random
import urllib.request
HOST =
PORT =
DB =
USER =
PASS =
def json_rpc(url, method, params):
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": random.randint(0, 1000000000),
}
req = urllib.request.Request(url=url, data=json.dumps(data).encode(), headers={
"Content-Type":"application/json",
})
reply = json.loads(urllib.request.urlopen(req).read().decode('UTF-8'))
if reply.get("error"):
raise Exception(reply["error"])
return reply["result"]
def call(url, service, method, *args):
return json_rpc(url, "call", {"service": service, "method": method, "args": args})
# log in the given database
url = "http://%s:%s/jsonrpc" % (HOST, PORT)
uid = call(url, "common", "login", DB, USER, PASS)
args = [{'journal_id': 7}]
kwargs = {'context': {'active_model': 'account.move', 'active_ids': [23]}}
payment_register_id = call(url, "object", "execute_kw", DB, uid, PASS, 'account.payment.register', 'create', args, kwargs)
call(url, "object", "execute", DB, uid, PASS, 'account.payment.register', 'action_create_payments', [payment_register_id])

Automatically select the selection fields in new pop up form with Context default_fieldname

I want to convert the record from CRM Leads to another model (Admission). I have created a button type=object to call the function:
def convert_to_admission(self, arg):
return {
'name': 'custom_admission_form',
'view_type': 'form',
'view_mode': 'tree',
'views': [(view_id, 'form')],
'res_model': 'op.admission',
'view_id': view_id,
'type': 'ir.actions.act_window',
'res_id': self.id,
'target': 'new',
'context': {
'default_street': value['street'],
'default_street2': value['street2'],
'default_mobile': value['phone'],
'default_birth_date': value['dob'],
'default_city': value['city'],
'default_state_id': value['state'],
'default_country_id': value['country'],
'default_first_name': value['first_name'],
'default_last_name': value['last_name'],
'default_email': value['email'],
'default_gender': value['gender'],
'default_prev_institute_id': 'baktuk',
'default_family_income': value['family_income'],
},
}
I can see the view form pop up with automatically filled record (first_name & last name); is it's possible to make it preselect the selection fields like country_id,gender, etc.?
To store in selection field grab value of database entry:
See the below example:-
eft_status = fields.Selection([
('pending', 'Pending'),
('done', 'Done')], string="EFT Status", default='pending')
In this tuple ('pending', 'Pending') > first one is the value which is stored in database and second one is the string which you can show in dropdown list of field.
So, most probably you can to select value is to grab something like this:-
'default_eft_status': 'pending'
This will select Pending Selection value from eft_status.
Feel free to ask if you can't understand.
well, as long as you said that some fields are updated correctly. you need to make sure that value['country'] is a number value and the value['gender'] holds a string value listed as in the field definition. you could check these value using print() function or enable debug mode.

How can I combine a warning message and update field value inside of onchange method? In odoo 9

In older versions of odoo (openerp 7), I used to do things like this:
#api.multi
#api.onchange('my_field')
def my_field_change(self, cr, uid, partner_ids, context=None):
if condition is True:
return {
'warning': {'title': _('Error'), 'message': _('Error message'),},
'value': { 'my_field': new_value },
}
If I want to do this in odoo 9, I have this code:
#api.multi
#api.onchange('my_field')
def my_field_change(self):
if condition is True:
return {
'warning': {'title': _('Error'), 'message': _('Error message'),},
'value': { 'my_field': new_value },
}
The warning window is displayed but the value field is ignored.
How can I change the value of the field?
In odoo Onchange method, you can't return value same as older version of odoo.
Onchange method will only return Warning and Domain.
#api.multi
#api.onchange('my_field')
def my_field_change(self):
self.field=value
return {
'warning': {'title': _('Error'), 'message': _('Error message'),},
}
In Odoo new api no need to return value in dict just assign value in relevant field.
Ex: sale.field=value
This may help you.

Button Click Event..Odoo8

I have a button named as action_list and it is placed in XML file and works ok. What I want is that I want to fetch data from my table like task_name and duration on button click and this should be displayed in a new wizard where target =new. Am trying the below code. please guide me in all cases
def action_list(self,cr,uid,ids,context=None):
cr.execute("SELECT task_name, duration FROM activity_track WHERE id =%s",ids)
result= map(lambda x: x[0], cr.fetchall())
return {
'type':'ir.actions.act_window',
'view_mode':'tree,form',
'view_type':'tree',
'domain':'[]',
'nodestroy': True,
'target': 'new',
'res_model':'activity.track',
}
You can do this by 2 ways
1./ Either you can pass the 'result' in the context, and you pass that context in your action along with other parameters like domain,target. Then you can get that value in your wizard from context variable
def action_list(self,cr,uid,ids,context=None):
cr.execute("SELECT task_name, duration FROM activity_track WHERE id =%s",ids)
result= map(lambda x: x[0], cr.fetchall())
context.update({myresult':result})
return {
'type':'ir.actions.act_window',
'view_mode':'tree,form',
'view_type':'tree',
'domain':'[]',
'nodestroy': True,
'context':context,
'target': 'new',
'res_model':'activity.track',
}
2./ In your wizard you get the 'active_ids', using this you can get the result directly in the wizard itself. active_ids will the ids same as which are passed in the button click event that you are trying to use. Following line will be used in the wizard.
current_ids =context.get('active_ids',False)

check customer's name in OpenERP

the customer, do I prevent the customer's name should not be the same as that already exist?
and if I can inherit the tree view mode?
You will need to put a sql constraint in the code. Below is the code I have written for you.
you will need to make a module to get this done. let me know if you need further help.
class res_partner(osv.osv):
_inherit = "res.partner"
_columns = {
'name': fields.char('Name', size=128, required=True, select=True),
}
_sql_constraints = [
('name', 'unique (name)',
'The name of the partner must be unique !')
]