Getting id from URL to filling wizard form, Odoo - odoo

I want to get id from url when i click the button.
This is URL, id is 69:
http://localhost:8069/web#id=69&cids=1&menu_id=385&action=507&model=inventory.menu&view_type=form
I need to get this id in many2one field.
This is my wizard py file:
from odoo import api,fields,models
class ReduceInventoryWizard(models.TransientModel):
_name = "reduce.inventory.wizard"
_description = "Reduce Inventory Wizard"
inventory_ids = fields.Many2one('inventory.menu', string="Ürün Referans No: ", default=lambda self: self.env['inventory.menu'].search([('id', '=', 69)], limit=1))
As you can see, ('id', '=', 69) this is running but just one product. I want the information of that product to come automatically when I click the button in which product.
I tried this one: ('id', '=', self.id). But is not working.

In this situation there should be active_id or better active_ids in Odoo's context.
So you just can set the default parameter to use a default method, which will either return a value or an empty recordset:
def default_my_many2one_field_id(self):
active_ids = self.env.context.get("active_ids")
if active_ids:
return self.env["another.model"].browse(active_ids[0])
return self.env["another.model"]
my_many2one_field_id = fields.Many2one(
comodel_name="another.model", string="My M2o Field",
default=default_my_many2one_field_id)

Related

How to get value on one field based on two different fields

So Im creating a hotel management module . I have the option to filter rooms based on bed_type and tag. Tag contains different facilities like AC, TV etc. So an user will come and select a bed_type and the facilities he wants and in the third field it should show the rooms that have the given configuration if not available an error messages should come. SO i created a onchange function to do this , but i dint know how to include the tags in it. Im doing it on odoo v14. m
This is the model for the room
from odoo import api, fields, models, _
class HotelRoom(models.Model):
_name = 'hotel.room'
_description = 'hotel room'
_rec_name = 'room_number'
room_number = fields.Char('Room Number', required=True)
room_rent = fields.Monetary('Room Rent')
tag = fields.Many2many('hotel.tags', string='Facilities')
dormitory_count = fields.Integer('Dormitory count')
bed_type = fields.Selection([
('single', 'Single'),
('double', 'Double'),
('dormitory', 'Dormitory')
], required=True, default='other')
This is the model for the reception
class HotelAccommodation(models.Model):
_name = 'accommodation.room'
_description = 'Reception'
bed_type = fields.Selection([
('single', 'Single'),
('double', 'Double'),
('dormitory', 'Dormitory')
], required=True, string= 'Bed type')
state = fields.Selection([
('draft','Draft'),
('check-in','Check-In'),
('check-out', "Check-Out"),
('cancel','Cancel'),
], required=True, default='draft', tracking=True)
tag = fields.Many2many('hotel.tags', string='Facilities')
room_id = fields.Many2one('hotel.room', string='Room')
Using this I can filter the rooms based on the bed_type but I need to have the tags as well.I tried giving it inside the domain but its not working .
#api.onchange('bed_type')
def filter_room(self):
for rec in self:
return {'domain': {'room_id': [('bed_type', '=', rec.bed_type)]}}
You need also to add the tag field to the domain and to the onchange decorator, so the method will be called when the tag field is modified.
The method is invoked on a pseudo-record that contains the values present in the form, you do not need to loop over self.
Try the following example:
#api.onchange('bed_type', 'tag')
def filter_room(self):
return {'domain': {'room_id': [('bed_type', '=', self.bed_type), ('tag', 'in', self.tag.ids)]}}
You can use _compute fields with the store option = True
take a look https://www.odoo.com/documentation/14.0/reference/orm.html#computed-fields

separate attribute from name products (Odoo 14)

sorry my english. I need a help with a issue I have. I defined a funtion to bring values attributes products however, when I run it, the result is
ValueError: Expected singleton: product.template.attribute.value(9, 25)
will somebody guide me to solve it? I dont know how to go on
class MRPSalesProduc(models.Model):
_inherit = 'mrp.production'
product_short_name = fields.Char('Productos')
#api.model
def create(self, vals):
product_short_name = self.env['sale.order'].search([('name', '=', vals[
'origin'])]).order_line.product_id.product_template_attribute_value.attribute_id
vals['product_short_name'] = product_short_nam
rec = super(MRPSalesProduc, self).create(vals)
return rec
You can use a related many2many field to get product attributes
Example:
class MRPSalesProduct(models.Model):
_inherit = 'mrp.production'
product_template_attribute_value_ids = fields.Many2many(related='product_id.product_template_attribute_value_ids')
Then use the man2many_tags widget to show the product attributes as tags:
<field name="product_template_attribute_value_ids" widget="many2many_tags"/>
Example (Product name):
class MRPProductsName(models.Model):
_inherit = 'mrp.production'
products_name = fields.Char(related="product_id.product_tmpl_id.name", string='Productos')
You have tried to search sale order and access all sale order lines.
If you pick first line from the sale order line, then it will be work as per your expectation. For example,
sale_order = self.env['sale.order'].search([('name', '=', vals['origin'])])
product_short_name = sale_order and sale_order.order_line[0].product_id.product_template_attribute_value.attribute_id
if product_short_name:
vals['product_short_name'] = product_short_nam
You can reference my blog https://odedrabhavesh.blogspot.com/2017/02/valueerror-expected-singleton-in-odoo.html for more about "ValueError: Expected singleton"

How to save One2many fields values?

I am adding custom One2many field in sale.order form view just below the sale.order.line.
I am computing values on_change it is displaying values but when I am going to save the sales order it is generating error that
ValueError: Wrong value for tax.lines.order_id: sale.order(24,)
Python:
class SaleOrderInherit(models.Model):
_inherit = ['sale.order']
tax_line = fields.One2many('tax.lines', 'order_id', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True, auto_join=True)
#on.change('partner_id')
def calculating_tax(self):
//After some code
self.env['tax.lines'].create({
'tax_id': tax['tid'],
'name': tax['name'],
'amount': tax['tax'],
'order_id': self.id
})
class TaxLines(models.Model):
_name = 'tax.lines'
tax_id = fields.Char('Tax Id')
name = fields.Char('Tax Name')
amount = fields.Char('Tax Amount')
order_id = fields.Many2one('sale.order', string='Tax Report', ondelete='cascade', index=True, copy=False)
Because I am creating one2many field before creating the order.
But is there any way to get rid of this problem.
Edit:
Error after replacing my code with Charif DZ code:
Never create records in onchange events they are immidiatly saved in database what if the user decided to cancel the order, instead of create use new with create an object but doesn't save it in database.
def calculating_tax(self):
//After some code
# to add record to your o2m use `|` oprator
# if you want to clear record before start adding new records make sure to empty your field first by an empty record set like this
# self.tax_line = self.env['tax.lines'] do this before the for loop that is used to fill-up the field not put it inside or you will get only the last record
self.tax_line |= self.env['tax.lines'].new({
'tax_id': tax['tid'],
'name': tax['name'],
'amount': tax['tax'],
# 'order_id': self.id remove the many2one because it's handled automaticly by the one2many
})
I hope this help you good luck

Fill up items from parent sale order to wizard

My goal is to get all items from parent quotation, to the wizard window.
I don't know i do this right way or not, but for now i can get all the products from quotation, and don't understand how to fill them into my wizard items line.
Quotation example
Wizard on that quotation
I remove the pieces of code which not matter.
from odoo import fields, models, api
import logging
class back_to_back_order(models.Model):
_name = "back.to.back.order"
_description = "Back to Back Order"
line_ids = fields.One2many('back.to.back.order.line','back_order_id', 'Order Lines', required=True)
def get_items_from_quotation(self, context):
items = []
quotation_id = context['id']
current_quotation = self.env['sale.order'].search([('id','=',quotation_id)])
if quotation_id == current_quotation.id:
for line in current_quotation.order_line:
item = {
'product_id': line.product_id,
'qty': line.product_uom_qty,
'price': line.price_unit,
'subtotal': line.price_unit*line.product_uom_qty
}
items.append(item)
class back_to_back_order_line(models.Model):
_name = "back.to.back.order.line"
_description = "Back to Back Order"
product_id = fields.Many2one('product.product', 'Product')
back_order_id = fields.Many2one('back.to.back.order', 'Back Order')
qty = fields.Float('Quantity')
price = fields.Float('Unit Price')
subtotal = fields.Float('Subtotal')
Firstly, if you are creating a wizard, then it's very likely you should be using models.TransientModel and not model.Model for your classes.
class back_to_back_order(models.TransientModel):
...
Wizard records are not meant to be persistent; they are automatically deleted from the database after a certain time. This is why they are called transient.
You mentioned you are already able to get the Sales Order Lines within your wizard, but you aren't sure how to fill your Back to Back Order Lines with the data.
One2many and Many2many use a special "commands" format to manipulate the set of records stored in/associated with the field.
I originally found these commands on another answer but they are also covered in the Documentation.
As for your specific application, you should be able to simply create your back.to.back.order.line records and they will be linked as long as you provide the back_order_id.
#api.multi
def get_items_from_quotation(self, context):
self.ensure_one()
b2b_line_obj = self.env['back.to.back.order.line']
quotation = self.env['sale.order'].browse(context['id'])
if quotation:
back_order_id = self.id
for line in quotation.order_line:
b2b_line_obj.create({
'back_order_id': back_order_id,
'product_id': line.product_id.id,
'qty': line.product_uom_qty,
'price': line.price_unit,
'subtotal': line.price_unit * line.product_uom_qty,
})

how get id with onchange for filtering

how can i retrieve the value of a many2one field or its ID from another model
for exemple:
class Contrat(models.Model):
_name = 'facturation.contrat'
contrat_parent_id = fields.Many2one('facturation.contrat', string='Numéro Contrat Client',
domain=[('is_prestataire', '=', False)])
class Lot(models.Model):
contrat_id = fields.Many2one('facturation.contrat', ondelete='cascade')
articlecontrat_ids = fields.Many2many('facturation.articleouvrage',string='Article Lot')
91/5000
i want that when i change contrat_parent_id i get it back to use it and filter my articles for field 'articlecontrat_ids'
here you need to use onchange event i'm assuming that facturation.articleouvrage have a m2o field named contrat_id
# in onchange event always put the name of the field that trigger the event
#api.onchange('contrat_parent_id ')
def onchange_contrat(self):
"""update the domain when we change the contrat"""
if self.contrat_parent_id :
# always check if the field is not empty
# return the domain like this but i don't know what you need exactly
return {'domain': {'articlecontrat_ids ' : [('contrat_id ', '=', self.contrat_parent_id.contract.id)]}}
else: # remove the domain
return {'domain': {'articlecontrat_ids ' : []}}
if you want to remove all records when user change the contrat_id but i think you make the user ungry
to reselect all this records.
self.articlecontrat_ids = [(5, 0, 0)]