I want to hide the create button based on the field "type" of model res.partner, by passing in the active_id from context to fields_view_get.
However, i am not able to access any fields, BESIDES the "id" field. I use logger to log the output/ value of the fields
My code:
class sale_order(models.Model):
_description = 'fields view get'
_inherit = "sale.order"
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
_logger = logging.getLogger(__name__)
res = super(sale_order, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
active_id = self.env.context.get('active_id', False)
customer = self.env['res.partner'].browse(active_id)
_logger.info('sale__customer.id: %d', customer.id)
_logger.info('sale__customer.name : %d', customer.name)
#I am getting output from the first log, but not the second
doc = etree.XML(res['arch'])
if view_type == 'tree':
for node_form in doc.xpath("//tree"):
node_form.set("create", 'false')
res['arch'] = etree.tostring(doc)
return res
sale_order()
I am getting output from the first log but not the second.
and I can see that customer.name is false but it is actually not.
How can I access the fields in the customer object?
Related
I have this model and method in odoo
class stock_transfer_details_items(models.TransientModel):
_inherit = 'stock.transfer_details_items'
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
q_auth = fields.Boolean(related='lot_id.q_auth', string="Quality Auth.")
needs_auth = fields.Boolean(related='product_id.needs_quality_auth')
#api.onchange("needs_auth")
def _onchange_NQA_domain(self):
domain = {'domain': {'lot_id': [('product_id', '=', rec.product_id.id)]}}
if rec.needs_auth:
domain = {'domain': {'lot_id': [('q_auth', '!=', False), ('product_id', '=', rec.product_id.id)]}}
return domain
All this code is working ok. My problem is that I need to apply this domain when the wizard opens. #api.depends means that the value changes depending on the value of needs_auth but it actually don't work if I don't interact with the checkbox of needs_auth. I want to apply the domain when the view is open and not interact with the needs_auth field, because the user will not be allow to interact.
The solution for your problem is to use fields_view_get.
It was already mentioned before here : https://stackoverflow.com/a/54825093/9796551
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(stock_transfer_details_items,self).fields_view_get(view_id=view_id,
view_type=view_type,
toolbar=toolbar,
submenu=submenu)
if view_type == 'form':
domain = "["
# Your condition...
domain += "]"
res['fields']['lot_id']['domain'] = domain
return res
Consider this:
#api.multi
#api.onchange('order_lines', 'order_lines.is_book_block', '')
#api.constrains('order_lines', 'order_lines.isbn')
def check_quantity(self):
location = self.printer_book_block.property_stock_supplier.id
for rec in self:
if rec.order_lines:
for line in rec.order_lines:
if line.qty > line.isbn.with_context({ 'location': location, }).qty_available >= 0:#line.isbn.qty_available in location:
rec.write({'state': 'awaitingraw'})
else:
rec.write({'state': 'work_in_progress', 'is_book_block': True})
When there is enough product quantity (isbn) on the specified location, change state of the document to work_in_progess and also change Boolean field is_book_block to True.
The state field is on the parent model:
class bsi_print_order(models.Model):
_name = 'bsi.print.order'
#api.model
def create(self, vals):
if vals.get('name', 'New') == 'New':
vals['name'] = self.env['ir.sequence'].next_by_code('bsi.print.order') or '/'
return super(bsi_print_order, self).create(vals)
name = fields.Char('Reference', required=True, index=True, copy=False, readonly='True', default='New')
order_lines = fields.One2many('bsi.print.order.lines', 'print_order', string="Order lines")
book_block = fields.Boolean(string="Book Block", default=True)
binding = fields.Boolean(string="Binding")
edging = fields.Boolean(string="Edging")
state = fields.Selection([
('draft','Draft'),
('awaitingraw','Awaiting raw materials'),
('work_in_progress','Print in Progress'),
('delivered','Delivered'),
('cancel','Cancel'),
], string="State")
The is_book_block field is on the child class One2many order_lines field:
class bsi_print_order_lines(models.Model):
_name = 'bsi.print.order.lines'
print_order = fields.Many2one('bsi.print.order', string="Print Order")
isbn = fields.Many2one('product.product', string="ISBN", domain="[('is_isbn', '=', True)]")
qty = fields.Integer(string="Quantity")
consumed_qty = fields.Integer(string="Quantity consumed")
remaining_qty = fields.Float(string="Remaining quantity")
is_book_block = fields.Boolean(string="Is Book Block Done")
is_binding = fields.Boolean(string="Is Binding Done")
is_edging = fields.Boolean(string="Is Edging Done")
isbns = fields.Many2one('worksheets.isbns', string="Worksheet ISBNS")
There are also other two fields is_binding and is_edging.
Anyways, knowing one is sufficient to figure out the other two (I guess, lol) so, since state is on the parent class, it works nicely, the state of the record actually changes, however, while there is no syntax error with is_book_block it should change to True, but it doesn't, so, I think this is because the method is looping on order_lines but it changes things on parent class only (bsi.production.order).
Any ideas?
From what i understand the is_book_blockis in the line when you loop through lines every line is a record it self you call write if you want to set more than field or just change that field:
# when you change just one field no need for write just
rec.state = 'work_in_progress' # is enough
# because rec.state will trigger write method
# but for more than one field use write to trigger it only one time
# line is a record too you can call write also if you want
line.is_book_block = True
One thing remove order_lines.is_book_blockfrom onchange decorator because you will trigger an infinitive call for the the method :
#api.onchange('order_lines')
I want to create recordset with product in my custom class from sale order after calling an event. I will create a record in sale.order and like creating invoice, I will create record in my custom module.
What I have done is:
In my custom class:
class LoadingSlip(models.Model):
_name = 'loading.slip'
_description = 'loading information'
partner_id = fields.Char("Customer Name")
order_date = fields.Date("Order Date")
expiration_date = fields.Date("Expiration Date")
# order_line = fields.One2many('sale.order.line', 'order_id', string="Order Lines")
product_line = fields.One2many('loading.product.line', 'loading_product', string="Loading Products")
class LoadingProduct(models.Model):
_name = 'loading.product.line'
_description = "Loading Product Informations"
products_id = fields.Many2one('product.product', string='Product',
ondelete='restrict', index=True)
quantity = fields.Float(string='Quantity', default=1)
loading_product = fields.Many2one('loading.slip', string="Loading Reference", ondelete='cascade', index='True')
In sale.order
class sale_func(models.Model):
_inherit = 'sale.order'
#api.multi
def _prepare_slip(self):
test.set_trace()
self.ensure_one()
slip = {
'partner_id': self.partner_id.name,
'order_date': self.date_order,
'expiration_date': self.validity_date,
}
return slip
#api.multi
def action_slip_create(self, grouped=False, final=False):
test.set_trace() # debug point
pprint(self)
inv_obj = self.env['loading.slip']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
slips={}
pprint(slips)
slipReferences={}
test.set_trace()
for order in self:
group_key = order.id
test.set_trace()
for line in order.order_line:
if group_key not in slips:
inv_data = order._prepare_slip()
loadingslip = inv_obj.create(inv_data)
slipReferences[loadingslip] = order
slips[group_key] = loadingslip
if line.product_uom_qty > 0:
line.slip_line_create(slips[group_key].id)
if not slips:
raise UserError(_('There is no loading slip line.'))
#api.multi
def create_slip(self):
test.set_trace()
pprint(self)
sale_orders = self.env['sale.order'].browse(self._context.get('active_ids', []))
self.action_slip_create(sale_orders)
In sale.order.line
class sales_order(models.Model):
_inherit="sale.order.line"
#api.multi
def _prepare_slip_line(self):
test.set_trace()
self.ensure_one()
res={}
pprint(res)
res={
'products_id': self.product_id.id or False,
'quantity': self.product_uom_qty
}
pprint(res)
#api.multi
def slip_line_create(self, loading_product):
test.set_trace()
prdct_order = self.env['loading.product.line']
for line in self:
vals = line._prepare_slip_line()
prdct_order.create(vals)
My error is:
> /home/diwap/odoo-dev/custom-addons/sales_ext_agni/models/models.py(196)slip_line_create()
195 vals = line._prepare_slip_line()
--> 196 prdct_order.create(vals)
197
ipdb> n
TypeError: "argument of type 'NoneType' is not iterable"
I have tried update and write method instead of create in line 196 but I could not get any result it's just come up with an empty field and also no error. However when I try the real thing and i.e. write() I get this error. Is there any wrong somewhere in my code or its just an horrible thing I am doing.
I tried to use api.constrain in odoo. The case is, I want to give condition to odoo if user missing one field, odoo will give some warning like alert, and user have to give some input to the previous field. This is my code :
class Provinc(models.Model):
_name = 'provinsi.model'
_rec_name ='prov'
prov = fields.Char(
string='Provinsi',
)
res_partner_ids = fields.One2many(
'res.partner',
'provinsi'
city_id = fields.One2many(
'city.model',
'provinsi_id'
)
class city(models.Model):
_name = 'kota.model'
_rec_name ='city'
city = fields.Char(
string='City',
)
res_partner_city = fields.One2many(
'res.partner',
'city'
)
provinsi_id = fields.Many2one(
'provinsi.model',
string='provinsi',
)
class Master_data(models.Model):
_inherit = 'res.partner'
provinsi = fields.Many2one(
'provinsi.model',
'provinsi',
)
city = fields.Many2one(
'city.model',
'city',
)
#api.onchange('provinsi')
def show_provinsi(self):
return {'domain': {'city': [('provinsi_id', '=', self.provinsi.id)]}}
#api.constrains('provinsi')
#api.onchange('city')
def show_kota(self):
for record in self:
if record.provinsi == False:
raise ValidationError("is gonna be error")
I have tried 2 ways. First, I put the api.constrain insode class City, and it's doesn't work,second ways I tried put the api.constrain like the code inside class master, and the result remains the same.
you only need onchang not any constrains to display warning!
#api.onchange('city')
def show_kota(self):
if self.city and not self.provinsi:
raise ValidationError("is gonna be error")
now if you select value in city field and provinsi missing value then it will display error msg
guessing field "city" and "provinsi" is in 'res.partner' form view!
If you want to check a field value is empty or not, just use required ="1" like:
<field name="provinsi" required="1"/>
Below code is asset inherited class . Here i will add 'place' field with 'Karn/Bang/Kengeri' and 'karn/bang/malleshwaram' for 'Karn/Bang/Kengeri' will add 'asset_catg_id' with A and B. then for 'karn/bang/malleshwaram' with Y and Z.
Now at calander inherited class . if i select 'place' with 'Karn/Bang/Kengeri' then next field 'asset_catg_id' i have to get only A and B drop down list. if again 'karn/bang/malleshwaram' then i have to get only Y,Z options . and previous selected 'asset_catg_id' values should get deleted . i have tried with domain filter option got keyvalue error
class asset_asset(osv.osv):
_inherit = "asset.asset"
#_name = "asset_asset"
_rec_name= "folio_num"
_columns = {
'name': fields.char('Asset Name', size=64),
'place': fields.many2one('asset.parentlocation', 'Location'),
'asset_catg_id' : fields.many2one('asset.catg', 'Asset Catg Selection', select=True, required=True),}
class asset_catg(osv.Model):
_name="asset.catg"
_rec_name='name1'
_description="Define Asset Catgs"
_columns={ 'name1':fields.char('Asset Catg Names',size=64,required=True),}
asset_catg()
class asset_parentlocation(osv.osv):
_name="asset.parentlocation"
_rec_name="location_name"
_columns = {
'location_name' : fields.char('Asset Location', required=True),
'parent_location' : fields.many2one('asset.parentlocation','Parent Location'),
'nameee':fields.many2one('ir.attachment','Attachments'),}
def name_get(self, cr, uid, ids, context=None):
if context is None:
context = {}
if not ids:
return []
reads = self.read(cr, uid, ids, ['location_name','parent_location'], context=context)
res = []
for record in reads:
name = record['location_name']
if record['parent_location']:
name = record['parent_location'][1]+' / '+name
res.append((record['id'], name))
return res
**Following code is calendar inherited class**
class calendar_event(osv.osv):
_inherit = "calendar.event"
_rec_name = 'number'
_columns = {
'number' : fields.char('Meeting ID',readonly=1),
#'place' : fields.many2one('stock.location','Substation Location',),
'place' : fields.many2one('asset.parentlocation','Substation Location',),
#'location' : fields.selection(STATUS_SELECTION,'Location', default='Board A'),
'asset_catg_id' : fields.many2one('asset.catg','Asset Catg Selection', domain="[('asset_catg_id', '=',place)]"),}
First your domain is wrong in a principle. Domain is what is "inside" a field, in other words in its model (for example field name or id in asset.catg model). So you should fix that one first.
If domain depends on another field, you can use onchange method to return domain (used placeholder place_id). Like this:
#api.onchange('place')
def onchange_place(self):
res = {}
if self.place:
res['domain'] = {'asset_catg_id': [('place_id', '=', self.place.id)]}
return res
P.S. This is example with new v8 api, but same principle applies to old api (you then don't nee to use decorator, also add cr, uid, ids on method and call it through your view. All of this not needed for new api). As it looks like you are still developing on old api.
Update
For old api:
def onchange_place(self,cr, uid, ids, place, context=None):
res = {}
if self.place: #on old api it will return id, instead of record
res['domain'] = {'asset_catg_id': [('place_id', '=', self.place)]}
return res
And then in your view (don't know what kind of view you are using):
<field name="place" on_change="onchange_place(place)"/>
Still you need to define some field in asset.catg so it would be used to match place field. For example:
'place_id': fields.many2one('asset.parentlocation', 'Place')
And then when you define asset category, you set which Place it should belong to. Then when you choose place calendar.event, onchange method will set domain on asset_catg_id field correctly.