This question has been flagged
2 Replies
4259 Views

I have fields for a quick access of the entities related to a project. For example:

class project(models.Model):
_name = "project.project"
_description = "Project"
_inherit = 'project.project'

production_order_ids = fields.One2many('mrp.production', 'project_id', 'Production orders')
purchase_order_ids = fields.One2many('purchase.order', 'project_id', 'Purchase orders')
....

I am trying to make a sale_order_ids in the project.project model. My first try did not work:

    sale_order_ids   = fields.One2many('sale.order', 'project_id', string='Sale orders')

because because the field sale.order.project_id is of type account.analytic.account.

A project.project object inherits from account.analytic.account. This query should work ok if they would share the same Id, but they do not. They can be the same thing from the business perspective but the domains expressions treat them as different entities. I don't want to theorize whether the ORM should map the entities equivalences or if the reference should b to project.project. Right now I look for a way to need a solution to easily navigate from the project to its sale orders.

So the navigation would be:

"project.project".analytic_account_id" -> sale.order".project_id

And the result would be the corresponding sale.order(s).

Option 1:  specify domains

sale_order_ids = fields.One2many('account.invoice', 'project_id',
domain = [('analytic_account_id','=',self._fields_id)],
string = 'Sale Orders')

...trying to look for  reference to the inverse column values. I got the error:

NameError: name 'self' is not defined

it seems that this kind of static domains can have reference to the browsing fields and constants but not to dynamic values or the inverse column (the corresponding column from the comodel). So I did try with a dynamic domain using a function:

sale_order_ids = fields.One2many('account.invoice', 'project_id',
domain = lambda self: [('analytic_account_id','=',self._fields_id)],
string = 'Sale Orders')

and I got:

'project.project' object has no attribute '_fields_id'" while parsing /opt/odoo_v8/addons/my_project/project_view.xml:4

 Then I look into the code (v8 - http://bit.ly/1GjYLEl), to see which is the parameter passed to the domain functions:

          # retrieve the records in the comodel
comodel = obj.pool[self._obj].browse(cr, user, [], context)
inverse = self._fields_id
domain = self._domain(obj) if callable(self._domain) else self._domain
domain = domain + [(inverse, 'in', ids)]
records = comodel.search(domain, limit=self._limit)

So the parameter is the project.project object not the field as I though. There we can see that it seems to be no way to refer to the comodel nor the inverse field (project_id) inside the domain function.

The inverse field is added always after calling the domain function:

             domain = domain + [(inverse, 'in', ids)]

Option 2: use relation field

The relation field would allow me follow a browse path. My try was:

    sale_order_ids   = fields.One2many('sale.order', 'project_id', related='analytic_account_id' string='Sale orders')

and then I got:

Warning: Type of related field project.project.sale_order_ids is inconsistent 
with project.project.analytic_account_id

It says "warning" but it crashs the updating process.I think it is telling me

You can only use related fields to browse to another entity just by its ID, not through other fields.

Which could be the way?
Avatar
Discard
Best Answer

You just need the relation field if you wanna show the sale orders in the project form, if you wanna show them when clicking on a button, there is no need to do the following

The initial thought could work if you add a many2one field on the sale.order model pointing back to the project.project model 

Option 4:

class project_analytic_account(models.Model):
_name = "account.analytic.account" 
_inherit = 'account.analytic.account'

sale_order_ids = fields.One2many('sale.order', 'project_id', string='Sale orders')

Through inheritance by delegation you could use the new field sale_order_ids in the project.project model and also in views 

 

Avatar
Discard
Author Best Answer

Option 3: use a computed field

sale_order_ids = fields.One2many('sale.order', compute='_get_sale_orders', string='Sale orders')

@api.model
def _get_sale_orders(self):
for record in self:
record.sale_order_ids = self.env['sale.order'].search([('project_id', '=', record.analytic_account_id.id)]).ids

Avatar
Discard