How to change state by clicking on button in inherited module - odoo

I Created a new module and inherited stock.picking module.In that added Accepted state between ready-to transfer and transfer state in warehouse. and a accept Button in header.
while clicking on accept button ,function is executing but state is not changing to accepted state.other functions of existing module are working correctly.
I added new accept selection field in existing module. i.e stock.picking
.py file
from openerp.osv import fields, osv
from openerp.exceptions import except_orm, Warning, ValidationError
import logging
class inventory_button_action(osv.osv):
_inherit = 'stock.picking'
def execute_accept_button(self, cr, uid, ids, context=None):
log = logging.getLogger(__name__)
log.info('######### Executed 11111 ########')
self.change_state_accept(cr, uid, ids, context=context)
def change_state_accept(self, cr, uid, ids, context=None):
log = logging.getLogger(__name__)
obj = self.pool.get('stock.picking')
obj.write(cr, uid, ids, {'state': 'accept'},context=context)
log.info('######### Executed 2222 ########')
xml file
<?xml version="1.0"?>
<openerp>
<data>
<record id="inventory_form_view" model="ir.ui.view">
<field name="name">inventory_status_form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//form/header/button[#name='do_enter_transfer_details']" position="before">
<button string="Accept" name="execute_accept_button" type="object" attrs="{'invisible':['|', ('state', 'in', ('draft','cancel','waiting','confirmed','partially_available','accept','done'))]}"/>
</xpath>
</field>
</record>
</data>
</openerp>
in stock.picking module
_columns = {
'name': fields.char('Reference', select=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=False),
'origin': fields.char('Source Document', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="Reference of the document", select=True),
'backorder_id': fields.many2one('stock.picking', 'Back Order of', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True, copy=False),
'note': fields.text('Notes'),
'move_type': fields.selection([('direct', 'Partial'), ('one', 'All at once')], 'Delivery Method', required=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, help="It specifies goods to be deliver partially or all at once"),
'state': fields.function(_state_get, type="selection", copy=False,
store={
'stock.picking': (lambda self, cr, uid, ids, ctx: ids, ['move_type'], 20),
'stock.move': (_get_pickings, ['state', 'picking_id', 'partially_available'], 20)},
selection=[
('draft', 'Draft'),
('cancel', 'Cancelled'),
('waiting', 'Waiting Another Operation'),
('confirmed', 'Waiting Availability'),
('partially_available', 'Partially Available'),
('assigned', 'Ready to Transfer'),('accept','Accepted'),
('done', 'Transferred'),
], string='Status', readonly=True, select=True, track_visibility='onchange')}

You do not need a browse record stock.picking to save a value.
When you write stok_obj.state = 'accept' you have just change instance value nothing will be saved in the database (available since odoo-8).
To change state to accept you can use write function:
openerp:
def execute_accept_button(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'accept'})
return True
Odoo:
#api.multi
def execute_accept_button(self):
self.write({'state': 'accept'})
return True

Try following:
def chnage_state_accept(self, cr, uid, ids, context=None):
self.write(cr,uid,ids,{'state':'accept'},context=context)
return <<return value if needed>>

Related

How to access sale.order fields from sale.order.line onchange?

i have override product_id_change() of sale.order.line its working fine.
Now my requirement is to get sale.order fields in my onchange so how can i get field value of sale.order from sale.order.line product_id_change()
here is my code odoov8
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
#how to access self.order_id
print "order id===", order_id
res = super(sale_order_line, self).product_id_change( cr, uid, ids, pricelist, product, qty=qty,uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,lang=lang, update_tax=update_tax, date_order= date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
return res
You can do it using following steps.
1.In On change method you can pass one argument parent.
<record model="ir.ui.view" id="sale_margin_sale_order_line">
<field name="name">sale.order.line.margin_and_quantities.view.form</field>
<field name="type">form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='order_line']/form[#string='Sales Order Lines']/group/group[1]/field[#name='product_id']"
position="attributes"> position="attributes">
<attribute name="on_change">
product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,
product_uos,name,parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position, True, context,parent)
</attribute>
</xpath>
</field>
</record>
In above view we have used position attributes option to replace on_change method.
In on_change method just add one parameter at last parent, parent means sale.order object.
product_id field is available in sale.order.line, you can access order_id using parent keyword in the view.
2.Inherit product_id_change method in py file.
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None,order_id=False):
res=super(sale_order,self).product_id_change(cr,uid,ids,pricelist,product,qty,uom,qty_uos,uos,name,partner_id,lang,update_tax,date_order,packaging,fiscal_position,flag,context)
return res
In above method order_id is available in method argument, so you
can directly access it.
If you have installed sale_stock module then you should inherit
product_id_change_with_wh method in py file & change position attributes in product_id_change_with_wh on_change in view, also
must give dependency of sale_stock in openerp.py file.
After that you will get order_id field in
product_id_change_with_wh on_change method & pass this parameter in on_change product_id method.
Ex :
def product_id_change_with_wh(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, warehouse_id=False, context=None,order_id=False):
context = context or {}
product_uom_obj = self.pool.get('product.uom')
product_obj = self.pool.get('product.product')
warning = {}
#UoM False due to hack which makes sure uom changes price, ... in product_id_change
res = self.product_id_change(cr, uid, ids, pricelist, product, qty=qty,
uom=False, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context,order_id=order_id)
This method is written in the old API so you have to browse the sale.order.line record, which is changed.
def product_id_change(
self, cr, uid, ids, pricelist, product, qty=0, uom=False,
qty_uos=0, uos=False, name='', partner_id=False, lang=False,
update_tax=True, date_order=False, packaging=False,
fiscal_position=False, flag=False, context=None):
line = self.browse(cr, uid, ids[0], context)
# print line.order_id.name
res = super(sale_order_line, self).product_id_change(
cr, uid, ids, pricelist, product, qty=qty,uom=uom,
qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id
lang=lang, update_tax=update_tax, date_order= date_order,
packaging=packaging, fiscal_position=fiscal_position,
flag=flag, context=context)
return res

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 achieve this functionality in Odoo?

I have been trying with sending mails whenever there is a leave request/approval/rejection in Leave request and I have been following the steps in the following link - https://www.odoo.com/forum/help-1/question/openerp-7-sending-email-to-manager-when-employee-applies-a-leave-7362
By following the above steps, messages do appear in Odoo Inbox but I am not able to get the mail delivered to mail client like thunderbird
Anyone kindly can give an opinion ?
Here is the code that you want,
Code for leave request:
def create(self, cr, uid, values, context=None):
res = super(hr_holidays, self).create(cr, uid, values, context=context)
template = self.pool.get('ir.model.data').get_object(cr, uid, 'hr_holidays_aspire', 'leave_request')
mail_id = self.pool.get('email.template').send_mail(cr, uid, template.id, res , force_send=True)
return res
Code for leave approve:
def holidays_validate(self, cr, uid, ids, context=None):
compose_ctx = dict(context,active_ids=ids)
search_domain = [('name', '=', 'Leave Approved')]
template_id = self.pool['email.template'].search(cr, uid, search_domain, context=context)[0]
compose_id = self.pool['mail.compose.message'].create(
cr, uid, {
'model': self._name,
'composition_mode': 'mass_mail',
'template_id': template_id,
'post': True,
'notify': True,
}, context=compose_ctx)
self.pool['mail.compose.message'].write(
cr, uid, [compose_id],
self.pool['mail.compose.message'].onchange_template_id(
cr, uid, [compose_id],
template_id, 'mass_mail', self._name, False,
context=compose_ctx)['value'],
context=compose_ctx)
self.pool['mail.compose.message'].send_mail(cr, uid, [compose_id], context=compose_ctx)
return True
Code for leave refuse:
def holidays_refuse(self, cr, uid, ids, context=None):
compose_ctx = dict(context,active_ids=ids)
search_domain = [('name', '=', 'Leave Refused')]
template_id = self.pool['email.template'].search(cr, uid, search_domain, context=context)[0]
compose_id = self.pool['mail.compose.message'].create(
cr, uid, {
'model': self._name,
'composition_mode': 'mass_mail',
'template_id': template_id,
'post': True,
'notify': True,
}, context=compose_ctx)
self.pool['mail.compose.message'].write(
cr, uid, [compose_id],
self.pool['mail.compose.message'].onchange_template_id(
cr, uid, [compose_id],
template_id, 'mass_mail', self._name, False,
context=compose_ctx)['value'],
context=compose_ctx)
self.pool['mail.compose.message'].send_mail(cr, uid, [compose_id], context=compose_ctx)
return super(hr_holidays, self).holidays_refuse(cr, uid, ids, context=context)
Here is the three different template for Leave request,approve and refuse respectively.
<!-- Templates for requesting leave -->
<record id="leave_request" model="email.template">
<field name="name">Leave Request</field>
<field name="subject">Leave Application from ${object.employee_id.name} [${object.employee_id.employee_no}].</field>
<field name="email_from">${object.employee_id.work_email}</field>
<field name="email_to">${object.employee_id.parent_id.work_email}</field>
<field name="model_id" ref="model_hr_holidays"/>
<field name="user_signature" eval="0"/>
<field name="body_html"><![CDATA[<p>Hi,</p>
<p> ${object.employee_id.name} [${object.employee_id.employee_no}] has applied for a leave application.</p><br/>
<p>Following are the applied leave details: </p>
<p>Leave type: ${object.holiday_status_id.name}</p>
<p>From Date: ${object.date_from}</p>
<p>To Date: ${object.date_to}</p>
<p>Number of days: ${object.number_of_days_temp}</p>
<p>Reason: ${object.name}</p>
<p>From Session: ${object.from_session}</p>
<p>To Session: ${object.to_session}</p>
<br/><br/>
<p>Regards, ${object.employee_id.name}</p>
]]></field>
</record>
<!-- Templates for approving leave -->
<record id="leave_approve" model="email.template">
<field name="name">Leave Approved</field>
<field name="subject">Your Leave Application has been Accepted.</field>
<field name="email_from">${object.employee_id.parent_id.work_email}</field>
<field name="email_to">${object.employee_id.work_email}</field>
<field name="model_id" ref="model_hr_holidays"/>
<field name="user_signature" eval="0"/>
<field name="body_html"><![CDATA[<p>Hi ${object.employee_id.name} [${object.employee_id.employee_no}], </p>
<p>Your leave application has been accepted.</p><br/>
<p>Leave type: ${object.holiday_status_id.name}</p>
<p>From Date: ${object.date_from}</p>
<p>To Date: ${object.date_to}</p>
<p>Number of days: ${object.number_of_days_temp}</p>
<p>Reason: ${object.name}</p>
<p>From Session: ${object.from_session}</p>
<p>To Session: ${object.to_session}</p>
<br/><br/>
<p>Regards, ${object.employee_id.parent_id.name}</p>
]]></field>
</record>
<!-- Templates for refusing leave -->
<record id="leave_refuse" model="email.template">
<field name="name">Leave Refused</field>
<field name="subject">Your Leave Application has been Refused.</field>
<field name="email_from">${object.employee_id.parent_id.work_email}</field>
<field name="email_to">${object.employee_id.work_email}</field>
<field name="model_id" ref="model_hr_holidays"/>
<field name="user_signature" eval="0"/>
<field name="body_html"><![CDATA[<p>Hi ${object.employee_id.name} [${object.employee_id.employee_no}], </p>
<p>Your leave application has been refused.</p><br/>
<p>Leave type: ${object.holiday_status_id.name}</p>
<p>From Date: ${object.date_from}</p>
<p>To Date: ${object.date_to}</p>
<p>Number of days: ${object.number_of_days_temp}</p>
<p>Reason: ${object.name}</p>
<p>From Session: ${object.from_session}</p>
<p>To Session: ${object.to_session}</p>
<br/><br/>
<p>Regards, ${object.employee_id.parent_id.name}</p>
]]></field>
</record>
Cheers !!!

Autofill some fields Openerp

Hi I am new to OpenERP7/Odoo7 and not really getting how to do this.
I have a existing records in my custom product module and I want to retrieve that record by entering only to my prodcode fields and want to autofill some fields.
I have been reading a lot on the internet, Odoo forums, but cannot find the answer or I just don't understand it. I already have post with regards to my problem
So if is there someone could give me an answer on how to achieve this, or direct me to a easy to understand explanation.
That would be great.
Here is I have done already
PYTHON---
class test_product(osv.Model):
_name = "test.product"
def name_change(self, cr, uid, ids, test_prodcode_id, prodname, desc, price, context=None):
return {
'value': {
'prodname': 'Plastic Ware',
'desc': 'Affordable Plastic Ware',
'price': 100.00,
}
}
_columns = {
'test_prodcode_id': fields.many2one('test.prodcode', 'Code'),
'prodname': fields.char('Name', size=32),
'desc': fields.char('Description', size=32),
'price': fields.float('Price',),
}
class test_prodcode(osv.Model):
_name = "test.prodcode"
_columns = {
'name': fields.char('Product Code', size=32),
}
XML----
<record id="test_product_form_view" model="ir.ui.view">
<field name="name">test.product.form.vew</field>
<field name="model">test.product</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Product" version="7.0">
<sheet>
<field name="test_prodcode_id" on_change="name_change(test_prodcode_id,prodname,desc,price)"/>
<field name="prodname"/>
<field name="desc"/>
<field name="price"/>
</sheet>
</form>
</field>
</record>
Yeah, I've had this problem too.
I've got the solution. Auto fill can be achieved by doing
_defaults = {}
, or, as in your example, by doing
class test_product(osv.Model):
_columns = {
'test_prodcode_id': fields.many2one('test.prodcode', 'Code'),
'prodname': fields.char('Name', size=32),
'desc': fields.char('Description', size=32),
'price': fields.float('Price',),
}
_defaults: {
'test_prodcode_id' : 'defaults_prodcode',
}
You can also assign a function that return the value of the defaults.
I have solution but it is not as exactly as you want but you can do like
this also.
You can use related for auto fill your other fields. Suppose you set
product_id it will auto fill product_name, desc and price regarding to
your product_id.
You can also see Example here :
https://stackoverflow.com/a/42453539/5161074

how to use functional field in record rule?

I am trying to achieve that all the users that are Hr managers should be allowed to see the records.
I have created a Functional Field:
def list_HRM(self, cr, uid, ids, field_name, arg, context):
attribute = {}
hr_managers = self.pool.get('hr.employee').search(cr, uid, ['&', ('department_id.name', '=', 'Human Resources'), ('manager', '=', True)], context=context)
hr_managers_uid = []
for record in hr_managers:
hr_managers_uid.append(self.pool.get('hr.employee').browse(cr, uid, record, context=context).user_id.id)
record = self.browse(cr, uid, ids)[0]
attribute[record.id] = str(uid in hr_managers_uid or uid==1)
return attribute
_columns={
'hr_managers_func' : fields.function(list_HRM, type='char', method=True, string='List of HR Managers'),
'always_true':fields.boolean()
}
_defaults={
'always_true':True
}
In .xml file:
<field name="always_true" invisible="1"/>
<field name="hr_managers_func" invisible="1"/>
In Record Rule:
['&','|',('state','=','hod_depart'),('state','=','hr_review'),('always_true','=',eval(hr_managers_func))]
I used field 'always_true' because of the record rule condition format i.e.
[('field_name','operator',values)].
I thought that rule will evaluate the functional field using eval
but unfortunately eval is not working on the record rule ,
I am getting this error:
NameError: name 'eval' is not defined
I could not think of more than this.
I saw few forum somewhat similar to my problem, they were using the related field to avoid the functional field in the record, but here I have to check whether the current user belong to hr managers or not .
I have tried explaining this in the best possible way, Looking forward for some reply.
To restrict on a function field, you need to define a fnct_search. The functional field per se becomes a dummy.
In your model:
def _my_functional_field_search(self, cr, uid, obj, name, args, context=None):
list_of_ids = [...]
return [('id', 'in', list_of_ids)]
_columns = {
'my_functional_field': fields.function(
lambda **x: True,
fnct_search=_my_functional_field_search,
type='boolean',
method=True,
),
}
And then in your security XML file:
<record id="your_rule_id" model="ir.rule">
<field name="name">Your Rule Name</field>
<field name="model_id" ref="model_the_model" />
<field name="groups" eval="[(4, ref('group_affected_group'))]" />
<field name="domain_force">[('my_functional_field', '=', True)]</field>
</record>