How to store default entered value in custom field of quantity on Hand.? - odoo

Need to store default value on qty in M.sqr and square meter like quantity on hand showing default entered value.
when i click on update button of quantity on Hand from product inventory page
then it should show me a previous entered value.
class stock_change_product_qty(osv.osv):
_inherit = 'stock.change.product.qty'
_columns = {
'new_quantity' : fields.float('Qty in Boxes'),
'squ_meter': fields.related('product_id','squ_meter', type='float', relation='product.product', string='Square Meter'),
'qty_char': fields.float('Qty in M.sqr', compute='_compute_qty_char'),
}
#api.depends('new_quantity', 'squ_meter')
def _compute_qty_char(self):
for record in self:
record.qty_char = record.new_quantity * record.squ_meter
view.xml
<field name="name">update_product_quantity inherit</field>
<field name="model">stock.change.product.qty</field>
<field name="inherit_id" ref="stock.view_change_product_quantity"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='new_quantity']" position="attributes">
<attribute name="string">Qty in Boxes</attribute>
</xpath>
<xpath expr="//field[#name='new_quantity']" position="replace">
<field name="new_quantity"/>
<field name="squ_meter"/>
<field name="qty_char"/>
</xpath>
</field>
</record>

A solution is to use a function as default value for your field:
odoo V8
from openerp import api, fields, models
class stock_change_product_qty(models.Model):
_inherit = 'stock.change.product.qty'
new_quantity = fields.Float(string='Qty in Boxes', default=1.0),
squ_meter = fields.Float(related='product_id.squ_meter', string='Square Meter', default=1.0),
qty_char = fields.Float('Qty in M.sqr', compute='_compute_qty_char'),
}
#api.one
#api.depends('new_quantity', 'squ_meter')
def _compute_qty_char(self):
for record in self:
record.qty_char = record.new_quantity * record.squ_meter
odoo V7
def _your_function(self, cr, uid, context=None):
your code here
...
...
...
return field_value
_defaults = {
'your_field' : _your_function,
}
#api.onchange
This decorator will trigger the call to the decorated function if any of the fields specified in the decorator is changed in the form:
#api.onchange('fieldx')
def do_stuff(self):
if self.fieldx == x:
self.fieldy = 'toto'
In previous sample self corresponds to the record currently edited on the form. When in on_change context all work is done in the cache. So you can alter RecordSet inside your function without being worried about altering database. That’s the main difference with #api.depends
At function return, differences between the cache and the RecordSet will be returned to the form.

Related

Why isn't this domain giving me results?

So I'm making this localization kind of module for Lebanon and am currently doing the location bit.
The intended functionality is to have the choices of governate, district and region restrict the choices the user can make by filtering out the irrelevant options.
Here are the models:
# -*- coding: utf-8 -*-
from odoo import models, fields, api
# Base model
class LebaneseLocation(models.Model):
_inherit = "res.partner"
governate_id = fields.Many2one("lebanon.governate", "Governate")
district_id = fields.Many2one("lebanon.district", "District")
region_id = fields.Many2one("lebanon.region", "Region")
# Child models with the necessary relations
class Governate(models.Model):
_name = "lebanon.governate"
name = fields.Char()
child_districts = fields.One2many("lebanon.district", "parent_governate",
"Child Districts")
class District(models.Model):
_name = "lebanon.district"
name = fields.Char()
parent_governate = fields.Many2one("lebanon.governate", "Parent Governate")
child_regions = fields.One2many("lebanon.region", "parent_district",
"Child Regions")
class Region(models.Model):
_name = "lebanon.region"
name = fields.Char()
parent_district = fields.Many2one("lebanon.district", "Parent District")
and the view file:
<?xml version="1.0"?>
<odoo>
<record id="view_res_partner_extended_location" model="ir.ui.view">
<field name="name">Contacts Custom</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="category_id" position="after">
<field name="governate_id" domain="[('child_districts','=?','district_id'),('child_districts.child_regions','=?','region_id')]"/>
<field name="district_id"/>
<field name="region_id"/>
</field>
</field>
</record>
</odoo>
And all the data was inputed via two data files, one makes the records without relations and the other updates the same records with relations.
I was testing things out with the Governate domain and it just kept returning nothing.
Is there some way to check what exactly these parameters i'm evaluating are returning? That would help a lot with debugging.
Edit: Here's a screenshot from Studio's menu for the domain, in case that's at all relevant for debugging (I avoid Studio like a plague usually)
Domain Image
I solved my issue by forgoing the XML approach and setting the domains using the onchange api call:
#api.onchange('governate_id', 'district_id', 'region_id')
def update_domains(self):
governate = self.governate_id.name
district = self.district_id.name
region = self.region_id.name
result = {}
result['domain']={
'governate_id':[('child_districts.name','=?', governate),
('child_districts.child_regions.name', '=?', region)],
'district_id':[('parent_governate.name', '=?', governate),
('child_regions.name', '=?', region)],
'region_id':[('parent_district.name', '=?', district),
('parent_district.parent_governate.name', '=?', governate)]
}
return result

Display multiple one2many field with different domain dynamically?

I have a model(modelA) with one2many field related to another model(modelB) and one of the fields in modelB is a category field, which is a many2one field. The requirement is to have a one2many field displayed for each category. So if there are 2 categories named 'category1' and 'category2', the form view of modelA should have 2 one2many fields, one which displays records of having category1 and another for category2(which could possibly done using domain).
For eg modelA and modelB has the following structure.
class classA(models.Model):
_name = 'modelA'
modelA_one2manyfield = fields.One2many('modelB', 'modelB_many2onefield')
class classB(models.Model):
_name = 'modelB'
name = fields.Char()
category = fields.Many2one('modelC')
modelB_many2onefield = fields.Many2one('modelA')
How would i go about implementing a form view for modelA so that for each category(which can be added by the user, hence there can be of any number of categories) there is a seperate one2many field.
What you are asking take a lot of time to give a very good answer one of the way that i think you need to try is override the fields_view_get because this is the method that retreive the view and here you can change the arch field to add a costum field take a look at this tutorial :
Tutorial for dynamic view
but i think you will have a problem, because even when you put the domain on the one2many field in XML, odoo will not filter
the record when the loading happen on the view :
<!-- here all record are shown but the expected behavior is the one2many should be empty -->
<field name="one2many_field_name" readonly="1" nolabel="1" domain="[('id', '=', False)]">
but when i add this field to the python declaration
# here no record will be shown on the view and that's what was expected
one2many_field_name = fields.One2many(..., domain=[('id', '=', False)])
so the question adding one2many field to arch via fields_view_get is easy but the problem is filtring data !!
It's technically not possible. Because you can't have 2 times the same field in the same view.
But you can create a specific widget to showing what you want. How you can see in the timesheet view (My Current timesheet menu).
This is a little tutorial to created a widget.
https://www.odoo.com/documentation/10.0/howtos/web.html#widgets-basics
This not an answer but you can say a tutorial example of dynamic view :
modul structur:
->dynamic_view
--> __ini__.py
--> models.py
--> views.xml
--> __manifest__.py
__manifest__.py :
# -*- coding: utf-8 -*-
{
'name' : 'Dynamic view',
'version' : '1.0',
'summary': 'Tutorial for Dynamic view',
'sequence': 30,
'description': """
This Module is for showing that you can update the code of the view
when it's called and even create new field without having to use python
code at all
""",
'category': 'StackOverFlow',
'depends' : ['base_setup',],
'data': [
'views.xml'
],
'installable': True,
'application': True,
'auto_install': False,
}
__init__.py :
# -*- coding: utf-8 -*-
from . import models
models.py :
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class Person(models.Model):
_name = "training.person"
name = fields.Char("Full name")
class Car(models.Model):
_name = "training.car"
name = fields.Char("Car name")
mark_id = fields.Many2one(comodel_name="training.mark", string="Mark")
owner_id = fields.Many2one(comodel_name="training.person", string="Owner")
person_view_id = "dynamic_view.dgapr_form_person"
# here default arch value body in the view contains only
# name field but as we create new mark we add others field
person_view_arch = """
<group>
<field name="name"/>
</group>
"""
class Mark(models.Model):
_name = "training.mark"
name = fields.Char("Mark")
#api.model
def create(self, values):
"""
when we create a category we add one2many field to person view
TODO: when we unlink a category we need to remove the one2many
name of field is : x_mark_{id of deleted record}
"""
rec_id = super(Mark, self).create(values)
o2m_field = {
# fields created using orm method must start with x_
"name": "x_mark_%s"% rec_id.id,
"field_description": "Mark %s" % rec_id.name,
"ttype": "one2many",
"relation": "training.car",
"relation_field": "owner_id",
"stored": True,
"domain": "[('mark_id','=', %s)]"%rec_id.id,
"model_id": self.env.ref("dynamic_view.model_training_person").id,
}
# add on2many field to ir.model.fields
self.env["ir.model.fields"].create(o2m_field)
self.update_arch()
return rec_id
def update_arch(self):
"""
when ever we create or delete a mark record
we need to update the the view to add new one2many field
if we want to hide the one2many field in view that don't have
any record we should create compute field to use attrs features
"""
view_id = self.env.ref(person_view_id)
o2m_fields_ids = self.env['ir.model.fields'].search(
[
('model_id', '=', self.env.ref("dynamic_view.model_training_person").id),
('ttype', 'like', 'one2many'),
('relation_field', 'like', 'owner_id')
])
o2many_arch = ""
for o2m_id in o2m_fields_ids:
o2many_arch = o2many_arch + """
<group col="1" string="%s">
<field name="%s" noloable="1" />
</group>
""" % (o2m_id.field_description, o2m_id.name,)
arch_begin = """
<form>
<sheet>
"""
arch_close = """
</sheet>
</form>
"""
arch_body = person_view_arch + o2many_arch
new_arch = arch_begin + arch_body + arch_close
# update the arch of the view in database
view_id.arch = new_arch
views.xml:
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="dgapr_form_car" model="ir.ui.view">
<field name="name">car.form</field>
<field name="model">training.car</field>
<field name="arch" type="xml">
<form >
<sheet>
<group>
<field name="name"/>
<field name="mark_id"/>
<field name="owner_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dgapr_action_car" model="ir.actions.act_window">
<field name="name">Cars</field>
<field name="res_model">training.car</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_root_training" name="Training"/>
<menuitem id="menu_ch_car" name="Cars" parent="menu_root_training" action="dgapr_action_car"/>
<record id="dgapr_form_person" model="ir.ui.view">
<field name="name">dgapr.form.person</field>
<field name="model">training.person</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
</group>
</sheet>
</form>
</field>
</record>
</data>
</odoo>
i found out that you can create field using ORM method even compute field. i think creating a widget is better but good to know that wen can create costum fields .
Hope this helps you
Note i didn't create a menu for person record but you can see the view by clicking on the owner_id in the car form if the new one2many field not shown just refresh the page.

Odoo 10: show field of model "sale.order" in form view of "account.invoice"

I usually create a new Database Structure Field by using the Debugging Mode, then Edit FormView and writing e.g. <field name="x_delivery_date"/>. Also I can show it later on the printed report like this:
<div name="x_delivery_date" t-if="doc.x_delivery_date">
<strong>Delivery Date:</strong>
<p t-field="doc.x_delivery_date"/>
</div>
But how do I display a field (commitment_date), which is available in the model (sale.order) in another models formview (account.invoice)? I guess that I have to use object relations or related field, but I don't know how. I hope somebody can help me. Many thanks in advance.
You can use related fields for that. You have to add two fields to account.invoice to do it.
class AccountInvoice(models.Model):
_inherit = "account.invoice"
order_id = fields.Many2one('sale.order', 'Related_order')
commitment_date = fields.Date(related='order_id.commitment_date')
Then you can use the commitment_date fields in account.invoice forms. The value of the field in sale.order will be reflected on the form right away. But be aware that changing the value of that field will change the value of that field on the sale.order as well.
EDIT
For reports just use the field like it is a regular field of account.invoice (so doc.commitment_date)
First you need to add a many2one field in account.invoice
class account_invoice(osv.osv):
_inherit = "account.invoice"
_columns = {
'source_id':fields.many2one('sale.order','Source')
}
Then inherit the _prepare_invoice function in sale_order. In this function you are going to pass the sale order id as source id to the account.invoice
class sale_order(osv.osv):
_inherit = "sale.order"
def _prepare_invoice(self, cr, uid, order, lines, context=None):
if context is None:
context = {}
journal_id = self.pool['account.invoice'].default_get(cr, uid, ['journal_id'], context=context)['journal_id']
if not journal_id:
raise osv.except_osv(_('Error!'),
_('Please define sales journal for this company: "%s" (id:%d).') % (order.company_id.name, order.company_id.id))
invoice_vals = {
'name': order.client_order_ref or '',
'origin': order.name,
'type': 'out_invoice',
#Sale order id as source_id
'source_id':order.id,
'reference': order.client_order_ref or order.name,
'account_id': order.partner_invoice_id.property_account_receivable.id,
'partner_id': order.partner_invoice_id.id,
'journal_id': journal_id,
'invoice_line': [(6, 0, lines)],
'currency_id': order.pricelist_id.currency_id.id,
'comment': order.note,
'payment_term': order.payment_term and order.payment_term.id or False,
'fiscal_position': order.fiscal_position.id or order.partner_invoice_id.property_account_position.id,
'date_invoice': context.get('date_invoice', False),
'company_id': order.company_id.id,
'user_id': order.user_id and order.user_id.id or False,
'section_id' : order.section_id.id
}
invoice_vals.update(self._inv_get(cr, uid, order, context=context))
return invoice_vals
Add this in View file
<record id="invoice_form" model="ir.ui.view">
<field name="name">account.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='date_invoice']" position="after">
<field name="source_id"/>
</xpath>
</field>
</record>
Now add this in your report file
<div name="x_delivery_date" t-if="doc.x_delivery_date">
<strong>Delivery Date:</strong>
<p t-field="doc.x_delivery_date"/>
<p t-field="doc.source_id.commitment_date"/>
</div>

How to add on_change in default field odoo 8

i want to add onchange function in module manufacturing (mrp.production)
in view.xml
<record model="ir.ui.view" id="partner_instructur_form_view">
<field name="name">mrp.production.form.instructur</field>
<field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[#name='location_dest_id']" position="after">
<field name="product_qty" on_change="onchange_hitung_kuota(product_qty, prod_qtys)"/>
<field name="prod_qtys" on_change="onchange_hitung_kuota(product_qty, prod_qtys)"/>
<field name="progres_persen" widget="progressbar"/>
</xpath>
</field>
</record>
in python
class ala_mrp_prod(osv.osv):
_inherit = 'mrp.production'
def onchange_hitung_kuota(self, cr, uid, ids, prod_qtys, product_qty):
kurangi = product_qty - prod_qtys
res = {
'value':{ 'progres_persen': (kurangi * 100) / product_qty}
}
return res
_columns = {
'prod_qtys':fields.integer('Jumlah Total'),
'progres_persen': fields.float('Progres'),
}
_defaults = {
'prod_qtys': 1,
}
ala_mrp_prod()
why product quantity show 2?
so if i input product_quantity 3 , jumlah total 5 progres 40%?
please help
You passed parameters in the wrong order.
product_qty should be the first in onchange_hitung_kuota() method:
def onchange_hitung_kuota(self, cr, uid, ids, product_qty, prod_qtys)
In odoo new api you do not need to modify the xml file. what you have to do is
class mrp_order(models.Model)
_inherit = 'mrp.production'
#api.onchange('product_qty', 'prod_qtys')
def onchange_hitung_kuota(self):
kurangi = product_qty - prod_qtys
self.progres_persen = (kurangi * 100) / self.product_qty
hope this helps!
I think you inverted the two parameters inside the onchange_hitung_kuota function

Master-detail relation, variable scope, passing variables, etc in openerp

I'm writing a warehouse management module and I came to the inventory step.
I need to make an inventory every now and then for each warehouse separately and each inventory operation will be kept in the database as a master-detail relation,
ie:
one record for the basic data such as id, date, warehouse_id etc. and
this will be recorded in a table created by (inventory) object.
many records will keep the details of the operation (one record for each material) recording the material id, inventory id, balance, etc. and this will be recorded in the table (inventory_lines).
During the data entry, when the user selects a material, I need to check its current balance and display it in the balance field. In order to do this, I'll need to know the warehouse id because every warehouse shall have separate inventories.
I have many materials stored in many warehouses.
For example: I can have a quantity of 5 pens in warehouse A and 10 pens in warehouse B and 6 pens in warehouse C.
First, I select the warehouse (A or B or C) --- let's say warehouse B
Then I select the material (Pen or notebook or whatever) --- let's say Pen
Now, I want to search the database to find the balance of (Pen) in (Warehouse B)
I can write something like this:
select balance from inventory_lines where material_id=mmmmmm and warehouse_id=wwwwww
So, I need to get the material id (mmmmm) and the warehouse id (wwwww)
And that will be done with each material I choose.
The warehouse id is in the column: inventory_id in the object: inventory
'warehouse_id' : fields.many2one('makhazen.warehouse', 'Warehouse Name',required=True),
The material id is in the column: material_id of the object inventory_line as in the picture in the question
'material_id' : fields.many2one('makhazen.material' ,'Material Name'),
I faced the following problem:
I could use the (on_change) method in the form view on the material_id field and could trigger a method to search for the balance in the database but I needed the warehouse_id which I couldn't get.
The questions are:
- How are this master-detail relationship is handled in openerp? how values are passed between the master table and the details table?
- How can we extend the scope of the warehouse_id so that it can be seen from any method in the module?
- I could change the values of the fields by calling a method and returning the desired values in a dictionary, but how to do the opposite (read them)?
It's very critical matter to me.
Firstly, you don't need the warehouse_id field in the wh_inventory_line class. You can always access it trough the the parent object:
inventory_line = self.pool.get('wh.inventory.line').browse(cr, uid, line_id)
wharehouse_id = inventory_line.inventory_id.warehouse_id.id
Secondly, in your case you can just pass the warehouse_id value as parameter to your onchange method. Something like this:
<field name="material_id"
on_change="onchange_material_id(material_id, warehouse_id)"/>
or, if you follow my first advice and remove the warehouse_id from wh_inventory_line:
<field name="material_id"
on_change="onchange_material_id(material_id, parent.warehouse_id)"/>
EDIT
After testing on OpenERP 6.0 I found some errors in your code. I'm just wondering how did you manage to run it.
First, you missed a quote (\') on the warehouse_id column definition of your wh.inventory model:
_columns = {
'date': fields.datetime('Date'),
'warehouse_id': fields.many2one('wh.warehouse', 'Warehouse Name, required=True),
Second, the fields.char() field definition takes at least size parameter additionally to the supplied Field Name. Again, you missed a quote on the following line:
'notes': fields.char('Notes),
Not an error but something you should consider too - you tagged your question with the openerp-7 tag. In OpenERP v7 inheriting from osv.osv is deprecated. Inherit from osv.Model instead.
If I insist on your errors it's because the solution I proposed to you is working fine on my side. So there must be some little error somewhere that prevents your code for doing what is expected.
Here is my test code. You can try it:
wh.py
# -*- encoding: utf-8 -*-
import netsvc
import pooler
from osv import fields, osv
class wh_warehouse(osv.osv):
_name = 'wh.warehouse'
_columns = {
'name': fields.char('Name', 128),
}
wh_warehouse()
class wh_material(osv.osv):
_name = 'wh.material'
_columns = {
'name': fields.char('Name', 128),
}
wh_material()
class wh_inventory(osv.osv):
_name = 'wh.inventory'
_columns = {
'date': fields.datetime('Date'),
'warehouse_id': fields.many2one('wh.warehouse', 'Warehouse Name', required=True),
'inventory_line_ids': fields.one2many('wh.inventory.line', 'inventory_id', 'Inventory'),
'notes': fields.char('Notes', 512),
'balance_track': fields.boolean('Balance Track'),
}
wh_inventory()
class wh_inventory_line(osv.osv):
_name = 'wh.inventory.line'
_columns = {
'inventory_id': fields.many2one('wh.inventory', 'Inventory'),
'material_id': fields.many2one('wh.material', 'Material'),
'balance': fields.float('Balance'),
'previous_balance': fields.float('Previous Balance'),
'notes': fields.char('Notes', 512),
}
def onchange_material_id(self, cr, uid, ids, material_id, warehouse_id):
return = {'value': {
'notes': 'Selected material {0} and warehouse {1}'.format(material_id, warehouse_id), }
}
wh_inventory_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
wh_view.xml
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_wh_inventory_form" model="ir.ui.view">
<field name="name">wh.inventory.form</field>
<field name="model">wh.inventory</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Warehouse Inventory">
<field name="date"/>
<field name="warehouse_id" widget="selection"/>
<field name="notes"/>
<field name="balance_track"/>
<field colspan="4" name="inventory_line_ids" widget="one2many_list">
<tree string="Details" editable="bottom">
<field name="material_id" widget="selection"
on_change="onchange_material_id(material_id, parent.warehouse_id)"/>
<field name="balance"/>
<field name="previous_balance"/>
<field name="notes"/>
</tree>
</field>
</form>
</field>
</record>
<record id="view_wh_inventory_tree" model="ir.ui.view">
<field name="name">wh.inventory.tree</field>
<field name="model">wh.inventory</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Warehouse Inventory">
<field name="date"/>
<field name="warehouse_id" widget="selection"/>
<field name="notes"/>
<field name="balance_track"/>
</tree>
</field>
</record>
<record id="action_wh_inventory_form" model="ir.actions.act_window">
<field name="name">Warehouse Inventory</field>
<field name="res_model">wh.inventory</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_wh_inventory_tree"/>
</record>
<menuitem
action="action_wh_inventory_form"
id="menu_wh_inventory_form"
parent="account.menu_finance"
/>
<!-- Sample data -->
<record id="warehouse_1" model="wh.warehouse">
<field name="name">Warehouse 1</field>
</record>
<record id="warehouse_2" model="wh.warehouse">
<field name="name">Warehouse 2</field>
</record>
<record id="warehouse_3" model="wh.warehouse">
<field name="name">Warehouse 3</field>
</record>
<record id="material_1" model="wh.material">
<field name="name">Material 1</field>
</record>
<record id="material_2" model="wh.material">
<field name="name">Material 2</field>
</record>
<record id="material_3" model="wh.material">
<field name="name">Material 3</field>
</record>
</data>
</openerp>