OpenERP: Add new selection on 'state' field by inheriting Sale Order - odoo

I really need to add an additional 'state' value on my Sale Order object. Since version 7.0, the 'sale_stock' module does exactly that already. When you try to do the same thing from your own module, your key,value just gets ignored. Is there any other alternative to achieve this?
As I found out, this seems to be an old time issue from two years ago as explained in this thread. A suggested workaround there was to do something like this:
_inherit = 'sale.order'
def __init__(self, pool, cr):
super(sale_order, self)._columns['state'].selection.append(('keyx', 'valuex'))
I found this approach logical, but it resulted in the following error:
`File "/home/nicolas/Eclipse/OpenERP/7.0/src/openerp/osv/orm.py", line 2958, in _auto_init
self._field_create(cr, context=context)
File "/home/nicolas/Eclipse/OpenERP/7.0/src/openerp/osv/orm.py", line 764, in _field_create
ir_model_fields_obj = self.pool.get('ir.model.fields')
AttributeError: 'sale.order' object has no attribute 'pool'`
Should this bug be reported at launchpad or is it an unintended use? What other possible solutions can you suggest? Thanks in advance.

try this
from openerp.osv import osv, fields
class sale_order(osv.osv):
_inherit = 'sale.order'
selection_list = [];#add your selection list here.
_columns = {
'state': fields.selection(selection_list,'State');#add necessary arguments
}
sale_order()

simply inherit the sale.order model and add your state field as it is which define in existing model , add the external state which you are required to add additionaly
for eg:
class sale_order(osv.osv)
_inherit ='sale.order'
_columns = {
'state': fields.selection([
('draft', 'Quotation'),
('waiting_date', 'Waiting Schedule'),
('manual', 'To Invoice'),
('progress', 'In Progress'),
('shipping_except', 'Shipping Exception'),
('invoice_except', 'Invoice Exception'),
('done', 'Done'),
('cancel', 'Cancelled'),
**('key','value')**,
This above would be your newly added selection value sequence dosen't matter.
], 'Order State', readonly=True, help="Gives the state of the quotation or sales order. \nThe exception state is automatically set when a cancel operation occurs in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception). \nThe 'Waiting Schedule' state is set when the invoice is confirmed but waiting for the scheduler to run on the order date.", select=True),
}
sale_order()
than abouve key value will be your additional selection field and you can set it any where in the squence as per your requirements.

having the same problem, I had a look at the thread, you noticed.
I guess that the problem comes from the fact that our modules and sale_stock are "in conflict" because they modify the same field ('state') in the sale.order object and are not depending of each other.
One solution is to modify your own module and adding 'sale_stock" in the 'depends' list of openerp.py :
depends : ['sale_stock',...]
You can see an example in this module which had another (key,value) in state field : http://bazaar.launchpad.net/~agaplan/agaplan-addons/7.0/files/head:/sale_double_validation/
Hope it helps

Related

How can I modify a selection field from another class in odoo 9?

I want to modify the "invoice_status" field from the "SaleOrder" class asociated to an invoice after the validation of that invoice.
The validation of an invoice is defined in the "AccountInvoice" class, inside the account module:
#api.multi
def invoice_validate(self):
...
I realised that the "name" field from "SaleOrder" class is related with the "origin" field from "AccountInvoice" class.
So, i modified the invoice_validate function like this:
#api.multi
def invoice_validate(self):
for invoice in self:
...
origin = self.origin
sale_order_id = self.env['sale.order'].search([('name', '=', origin)])[0].id
sale_order_obj = self.env['sale.order'].browse(sale_order_id)
sale_order_obj.write({'invoice_status': 'invoiced'})
return self.write({'state': 'open'})
For some reason, the write parte doesn't work.
That is the official definition of the "invoice_status" field from SaleOrder class:
invoice_status = fields.Selection([
('upselling', 'Upselling Opportunity'),
('invoiced', 'Fully Invoiced'),
('to invoice', 'To Invoice'),
('no', 'Nothing to Invoice')
], string='Invoice Status', compute='_get_invoiced', store=True, readonly=True, default='no')
You cannot set the value of invoice_status because it is a compute field. Even if you set it's value, it will be recomputed again when the field it depends on is changed and will eventually find the value it is supposed to have --and write that value instead of yours.
Odoo made it so that it work (it will say invoiced when the order is invoiced). So I don't think you need to do it maually. If you badly need to have your value stored, you should change that field so that it is not computed anymore, or create another field.
Check the selection_add attribute of the Selection class.
If you want to add some items to a selection field you have to redefine it in another class that inherits from the same model and declare it like this:
invoice_status = fields.Selection(selection_add=[("state", "open")])
Check the Selection class documentation and search for selection_add in your codebase to see some examples.

How to send multiple values in many2many field in odoo?

I am trying to generate purchase order from manufacturing order.I have created many2many field for getting multiple products.I want to send multiple product ids to my custom function.I am able to send 1 value but sending more than one gives error as Expected singleton: product.template(4, 3).
from openerp import models,fields,api
class generate_purchase_order(models.Model):
_name = 'mrp_to_purchase_order'
product_id = fields.Many2many('product.template',string='Products',required=True)
#api.multi
def generate_purchase_order2(self):
for wizard in self:
mrp_obj = self.env['mrp.production']
mrp_obj.generate_purchase_order(wizard.product_id.id) #function call
return { 'type': 'ir.actions.act_window_close'}
mrp_custom.py,
from openerp import models,api
class mrp_production(models.Model):
_inherit = 'mrp.production'
#api.multi
def generate_purchase_order(self,product_id):
purchase_line_obj = self.env['purchase.order.line']
context = self._context
for order in self.browse(context['active_ids']):
for line in order.bom_id.bom_line_ids:
if line.product_id.id != product_id:#problem line
continue
#rest of code
singleton: product.template(4, 3)
This error means that code is expecting single record not recordset, so you must change code to allow recordset using or make ensureone with try-catch and avoid errors. Thats general information.
Now if you want to get multiple records from many2many its not problem at all, you must pass this many2many object only and then work with it.
After getting many2many object to work with every record from this recordset you must use for record in recordset:
Also wizard.product_id.id this is error!!! product_id is many2many so you must pass product_id or if you want to browse by yourself you must pass product_id.ids

How can I create an alias name of a relational field in Odoo?

I need to create a model, to have backward compatibility with older field names.
This way,
I can develop modules that could read the "new" fields, but migrating the old ones is not necessary for this to work.
This works only for reading or presenting the fields, but not for writing them.
So I thought it would be good to create an alias for each field, and made this:
from openerp import models, fields, api
class backward_compatibility(models.Model):
_description = 'Backward compatibility'
_inherit = 'account.invoice'
new_document_class_id = fields.Integer(
compute='_comp_new_doc_class', string='Tipo')
new_document_number = fields.Char(
compute='_comp_new_doc_number', string='Folio')
#api.multi
def _comp_new_doc_class(self):
for record in self:
try:
record.new_document_class_id = record.old_document_class_id
except:
pass
#api.multi
def _comp_new_doc_number(self):
for record in self:
try:
record.new_document_number = record.old_document_number
except:
pass
This approach works for the Char field, but it doesn't for the Integer (Many2one).
What ideas do you have to make this work? Should I replicate the relationship in the new field?
oldname: the previous name of this field, so that ORM can rename it automatically at migration
Try to use "oldname". I saw this in the core modules. Never used personally.
_inherit = 'res.partner'
_columns = {
'barcode' : fields.char('Barcode', help="BarCode", oldname='ean13'),
}
Also dummy fields are user to help with backward compatibility.
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),

How to resolve this error in OpenErp?

I have been trying the following code in openerp and I had been getting this error
The operation cannot be completed, probably due to the following:
- deletion: you may be trying to delete a record while other records still reference it
- creation/update: a mandatory field is not correctly set
[object with reference: name - name]
In my py file, i had inherited one module
class hr_expense_expense(osv.osv):
_name = "hr.expense.expense"
_inherit = "hr.expense.expense"
_inherits = {'hr.employee':'first_approver'}
You don't give details, but I'm pretty sure the _inherits line should be removed. You probably made a confusion and actually want to add Many2one relation.

OpenERP one2many issue

I have the following:
shipment_obj = self.pool.get('stock.picking.in').browse(cr, uid, context.get('active_id'))
This returns correct object, I can access properties, but when I access the O2m field "move_lines", it returns None object and cannot iterate.
Do I need special way to access the products for the specific incoming shipment?
This is in existing OpenERP:
'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
'product_id': fields.related('move_lines', 'product_id', type='many2one', relation='product.product', string='Product'),
stock.picking.in , stock.picking.out and stock.picking are actually the same table stock_picking and stock.picking is considered as the base of both stock.picking.in and stock.picking.out. I think this functionality still have some issues and it is solved in openerp v8.So when you need to browse the object, use the stock.picking whether you are browsing for stock.picking.in nor stock.picking.out
when using
shipment_obj = self.pool.get('stock.picking.in').browse(cr, uid, context.get('active_id'))
here you will get a list of browse records, you can access the one2many field move_lines like
for shipment_id in shipment_obj:
move_lines = shipment_id.move_lines
here you will get the move_lines of each records of the list...
Needed to add this which solves the problem:
if context is not None and context.get('active_id'):
it is the way I thought the method was called that didn't need to check context and active_id since there would always be a context and active_id, I was wrong.