I have create a list view with the help of psql query with _auto = False. So there is not model registered against this. Now i want to customize this click event on the records that whenever a user click on any records i want to pass an order_id and then redirect user to that particular order detail screen.
Edit
View
<odoo>
<data>
<record id="amgl_dashboard_tree" model="ir.ui.view">
<field name="name">Dashboard</field>
<field name="model">amgl.dashboard</field>
<field name="arch" type="xml">
<tree default_order="state desc" decoration-bf ="state in ('expecting','pending','completed')" decoration-info="state=='expecting'" decoration-danger="state=='pending'" decoration-succes="state=='completed'" string="Dashboard" create="false" edit="false">
<field name="order_id" invisible="1"/>
<button name="view_record" type="object" string="View Record" custom="click" class="oe_highlight"/>
<field name="first_name"/>
<field name="last_name"/>
<field name="account_number"/>
<field name="product"/>
<field name="quantity"/>
<field name="total_weight"/>
<field name="state"/>
</tree>
</field>
</record>
</data>
</odoo>
.Py
class Dashboard(models.Model):
_name = 'amgl.dashboard'
_auto = False
#api.multi
def view_record(self):
print self
#api.model_cr
def init(self):
tools.drop_view_if_exists(self._cr, 'dashboard')
self._cr.execute("""
CREATE or REPLACE VIEW amgl_dashboard AS (
SELECT
row_number() OVER () AS id,
c.name AS first_name,
c.last_name AS last_name,
c.account_type AS account_type,
c.account_number AS account_number,
(select name from amgl_products where id = ol.products) AS product,
ol.quantity AS quantity,
(CASE
WHEN (select weight_unit from amgl_products where id = ol.products) = 'oz'
THEN
(select weight_per_piece from public.amgl_products where id = ol.products) * ol.quantity
WHEN (select weight_unit from amgl_products where id = ol.products) = 'gram'
THEN
((select weight_per_piece from public.amgl_products where id = ol.products) / 28.34952) * ol.quantity
WHEN (select weight_unit from amgl_products where id = ol.products) = 'pounds'
THEN
((select weight_per_piece from amgl_products where id = ol.products) * 16) * ol.quantity
WHEN (select weight_unit from amgl_products where id = ol.products) = 'kg'
THEN
((select weight_per_piece from amgl_products where id = ol.products) / 0.02834952) * ol.quantity
ELSE 0.0
END) AS total_weight,
o.state AS state,
o.id AS order_id
FROM amgl_order AS o
INNER JOIN amgl_customer AS c ON c.id = o.customer_id
INNER JOIN amgl_order_line AS ol ON ol.order_id = o.id
)""")
name = fields.Char()
first_name = fields.Char(string="First Name")
last_name = fields.Char(string="Last Name")
account_type = fields.Char(string="Account Type")
account_number = fields.Char(string="Account Number")
product = fields.Char(string="Product")
quantity = fields.Float(string="Quantity")
total_weight = fields.Float(string="Total Weight")
state = fields.Selection([('expecting', 'Expecting'), ('pending', 'Pending'),
('completed', 'Completed'), ('waiting', 'Waiting For Approval')],
'Status', default='expecting')
order_id = fields.Integer(string="Order Id")
Action
<record id="amgl.dashboard_action_window" model="ir.actions.act_window">
<field name="name">Dashboard</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">amgl.dashboard</field>
<field name="view_mode">tree</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
<!-- Add Text Here -->
</p><p>
<!-- More details about what a user can do with this object will be OK -->
</p>
</field>
</record>
Debugger
Self._context
Self
I think there are a couple of ways this could possibly work. I'm not 100% certain either of them will, but I'll give you the general ideas.
XML Only Solution
George has the main idea correct - you need to create an action to manage what you're wanting to do.
The important distinction is that you seem to want the list view to display one model (amgl.dashboard) but the form view to display another (sale.order)
Normally, I would suggest you create a button and display it in the list view to take the user directly to the sales order form. However, you may also be able to use a standard act_window action with the help of src_model.
Example from core:
Odoo uses the button below to invoke the action, which results in the user being able to go to the stock.location form view and go to the product.product list. You are essentially wanting to do the opposite of this with different models and without the button.
<button string="Products"
class="oe_stat_button"
icon="fa-filter" name="%(act_product_location_open)d" type="action"
context="{'location_id': active_id}"
/>
<act_window
id="act_product_location_open"
name="Products"
src_model="stock.location"
res_model="product.product"
context="{'location': active_id,
'search_default_real_stock_available': 1,
'search_default_virtual_stock_available': 1,
'search_default_virtual_stock_negative': 1,
'search_default_real_stock_negative': 1}"/>
Python Solution:
Assuming your view_record method is being called already, you can return the "View Sales Order form" action directly from the method itself.
# Make sure these imports are called in your file
# If you are on Odoo 9 or earlier, you must use openerp instead of odoo
from odoo import _
from odoo.exceptions import ValidationError
class Dashboard(models.Model):
_name = 'amgl.dashboard'
_auto = False
#api.multi
def view_record(self):
"""Return a Window Action to view the Sales Order form"""
self.ensure_one()
action = self.env.ref('sale.action_orders')
form = self.env.ref('sale.view_order_form', False)
if not (action or form):
raise ValidationError(_("Sales Orders Action or Form not found!"))
return {
'name': action.name,
'help': action.help,
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'views': [(form_id.id, 'form')]
'res_model': action.res_model,
'res_id': self._context.get('id'),
'target': 'current',
'context': {},
}
When you click a record on a listview an action is executed that moves you from the listview to a `formview.
There always exists a default action but if you want to pass some extra parameters you have to define your own. For a concrete example take a look at the sale.action_quotations action. This action moves the user from view1 to view2 (list to form for example)
https://github.com/OCA/OCB/blob/10.0/addons/sale/views/sale_views.xml#L518
<record id="action_quotations" model="ir.actions.act_window">
...
<field name="context">{'hide_sale': True}</field>
...
</record
This action is responsible for moving the user in Quotations between views. See how the context is passed. You only need tree,form on the view_mode here.
Related
I am using Odoo 10-e. I created a custom class for order
class Order(models.Model):
_name = 'amgl.order'
_description = 'Use this class to maintain all transaction in system.'
name = fields.Char(string='Name',readonly=True)
order_line = fields.One2many('amgl.order_line', 'order_id', string='Order Lines')
total_qty = fields.Float(string='Total Expected')
total_received_qty = fields.Float(string='Total Received Quantity')
customer_id = fields.Many2one('amgl.customer', string='Customers', required=True)
is_pending = fields.Boolean()
date_opened = fields.Datetime('Date Opened', required=True)
date_received = fields.Datetime('Date Received')
I also created a view for this class which show all records in tree view . Now i want to create another view named 'Pending Orders' in which i want to show all order where is_pending is true. I am new maybe that's why i am unable to find any example in Odoo Code base.
For this you don't need to create a new view just create a new menu and action and filter the records using domain.
<record id="action2_...." model="ir.actions.act_window" >
<field name="name"> Action Title </field>
....same as the first action...
<field name="res_model">your.model</fiel>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_pending', '=', True)] </field>
</record>
<menuitem ..... action="action2_.." />
NB: action can have properties like domain ,context, view_id, search_view_id, view_ids ... etc best way to learn is read about them and see the code in odoo.
The below view is not created. What is the issue?
Method:
def daily_flash_report_tree(self, cr, uid, ids, context=None):
sql = """
CREATE OR REPLACE VIEW report_view AS (
SELECT
id,name,job
from
sales_summary limit 10
)
"""
cr.execute(sql)
return {
'name': "Daily Flash Report",
'view_type': 'form',
'view_mode': 'tree',
'res_model': 'daliy.flash.report',
'type': 'ir.actions.act_window',
'context': {"search_default_group_period": 1},
}
Object:
class daily_flah_report_new(osv.osv):
_name = "daliy.flash.report"
_auto = False
_columns = {
'name': fields.char('Name'),
'job': fields.char('Job'),
}
View:
<record id="drill_flash_report_flash" model="ir.ui.view">
<field name="name">Report</field>
<field name="model">daliy.flash.report</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="job" />
</tree>
</field>
</record>
<record id="drill_flash_report_action" model="ir.actions.act_window">
<field name="name">Net Revenue</field>
<field name="res_model">daliy.flash.report</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
<field name="context">{"search_default_group_period": 1}</field>
</record>
please notice that you created view named "report_view"
CREATE OR REPLACE VIEW report_view AS (
SELECT
id,name,job
from
sales_summary limit 10
)
Because your object is daliy.flash.report so your default table of your object is daliy_flash_report
_name = "daliy.flash.report"
_auto = False
They are different, you should make sure name of table of object is same as name of the view.
Solution: choose 1 or 2.
You should create view named daliy_flash_report by below comment
CREATE OR REPLACE VIEW daliy_flash_report AS (
SELECT
id,name,job
from
sales_summary limit 10
)
Use attribute _table in your object to indicate table name.
class daily_flah_report_new(osv.osv):
_name = "daliy.flash.report"
_auto = False
_table = "report_view"
Good luck
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>
I need to create company and right away create contact that bound to that company:
vals = {...}
company = self.env['res.partner'].create(vals)
vals = {'company_id': company.id, ...}
contact = self.env['res.partner'].create(vals)
But odoo says: DETAIL: Key (company_id)=(49) is not present in table "res_company".
Transaction is not commited yet (as i suppose).
So how can i use field of just created records?
Method launched in ir.cron:
Method called like this:
<record model="ir.cron" id="ir_cron_load_data">
<field name="name">Load</field>
<field eval="False" name="active" />
<field name="interval_number">24</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field name="priority">100</field>
<field name="doall" eval="False"/>
<field name="model" eval="'sap_contacts'"/>
<field name="function" eval="'action_load_data'"/>
<field name="args" eval="'()'"/>
</record>
vals = {...}
company = self.env['res.partner'].create(vals)
vals = {'company_id': company.id, ...}
contact = self.env['res.partner'].create(vals)
The company_id field is a relational field between the res_partner and res_company tables. You try to create a record on the res_partner using the vals, the vals has a company_id key that has a company.id as its value. The company.id that you have there is the id of the new record you created on the res.partner table.
You have to create the company in the res.company table:
company = self.env['res.company'].create(some_vals)
and then get the id of that company company.id
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.