I want to create a virtual Many2many field for informational purpose only. Is it possible to compute and populate Many2many field without storing the generated virtual records?
Yes, It is possible to create Virtual Many2many field for informational purpose. Please see the below sample code,
#api.one
#api.depends(
'move_id.line_id.account_id',
'move_id.line_id.reconcile_id.line_id',
'move_id.line_id.reconcile_partial_id.line_partial_ids',
)
def _compute_move_lines(self):
# Give Journal Items related to the payment reconciled to this invoice.
# Return partial and total payments related to the selected invoice.
self.move_lines = self.env['account.move.line']
if not self.move_id:
return
data_lines = self.move_id.line_id.filtered(lambda l: l.account_id == self.account_id)
partial_lines = self.env['account.move.line']
for data_line in data_lines:
if data_line.reconcile_id:
lines = data_line.reconcile_id.line_id
elif data_line.reconcile_partial_id:
lines = data_line.reconcile_partial_id.line_partial_ids
else:
lines = self.env['account.move.line']
partial_lines += data_line
self.move_lines = lines - partial_lines
move_lines = fields.Many2many('account.move.line', string='Entry Lines',
compute='_compute_move_lines')
You can see above example in /addons/account/account_invoice.py file in the odoo addons.
Related
I am using odoo 13. I have a custom field weight in Purchase order line.
I want to copying the value of this field to custom field in stock move.
I know that to transfer the value of the field from sale order to stock move I can do it in the following way.
class StockMoveLine(models.Model):
_inherit = 'stock.move'
weight = fields.Float(
compute='_compute_weight' )
def _compute_weight(self):
for move in self:
if not (move.picking_id and move.picking_id.group_id):
continue
picking = move.picking_id
sale_order = self.env['sale.order'].sudo().search([
('procurement_group_id', '=', picking.group_id.id)], limit=1)
# print(picking)
if sale_order:
for line in sale_order.order_line:
if line.product_id.id != move.product_id.id:
continue
move.update({
'weight': line.weight,
})
continue
else:
# move.update({
# 'weight': move.weight,
# })
However I find myself stuck in the else to pass the field from purchase to stock move
You can use the purchase_line_id field on stock.move which is link to purchase.order.line
Code - PoL Reference in Stock Move
If you're inheriting stock.move, then change your model name to class StockMove(models.Model): instead of class StockMoveLine(models.Model):.
Try using #api.depends on your compute function.
I have created a new custom module to include width and lenght of a product as attributes with custom values, and I need to update the price_unit of the sales order line with the current unit price multiplied by the (lenght*witdh) value, so I can have the price per surface unit in the product card, and the price per total surface in the sales order line.
I use the product configurator and this is my code:
from odoo import models, fields, api
# import pymsgbox
class aurea_calculated_field_line(models.Model):
_inherit = 'sale.order.line'
field_superficie = fields.Float('Superficie')
field_alto = fields.Integer('Alto')
field_ancho = fields.Integer('Ancho')
#api.onchange('field_alto', 'field_ancho', 'product_uom_qty', 'quantity')
def _value_pc5(self):
for record in self:
record.field_superficie = record.field_ancho * record.field_alto
self.price_unit = float(self.field_superficie) * self.product_id.lst_price
#api.onchange('product_id')
def _value_pc4(self):
if not self.product_custom_attribute_value_ids and not self.product_no_variant_attribute_value_ids:
return ""
for pacv in self.product_custom_attribute_value_ids:
if pacv.custom_product_template_attribute_value_id.display_name == 'Largo: Largo':
self.field_alto = pacv.custom_value
if pacv.custom_product_template_attribute_value_id.display_name == 'Ancho: Ancho':
self.field_ancho = pacv.custom_value
It works fine, but the problem is when I change the product quantity the unit price is reset to the product pricelist price.
Any suggestions?
Thanks in advance
I looked at this a bit. I didn't reproduce the problem but here is something you probably can work with.
In Odoo13 source code in file addons/sale/models/sale.py on line 1614 is a method which causes behavior you have problem with:
#api.onchange('product_uom', 'product_uom_qty')
def product_uom_change(self):
if not self.product_uom or not self.product_id:
self.price_unit = 0.0
return
if self.order_id.pricelist_id and self.order_id.partner_id:
product = self.product_id.with_context(
lang=self.order_id.partner_id.lang,
partner=self.order_id.partner_id,
quantity=self.product_uom_qty,
date=self.order_id.date_order,
pricelist=self.order_id.pricelist_id.id,
uom=self.product_uom.id,
fiscal_position=self.env.context.get('fiscal_position')
)
self.price_unit = self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_id, self.company_id)
This re-calculates unit price when product quantity is changed. You'd have to overwrite this method in your code. Easiest way would be add this to your aurea_calculated_field_line-class.
def product_uom_change(self):
return
But this needs a lot of testing to make sure that some other feature does not break because of this.
I have records in the stock.move table that has One2many relation to stock.move.reconcile with column move_to_id which is the ID of another record in stock.move table. So this chain can be thousands of records.
As you can see in my example I loop trough all records and go down tier by tier, but as I said before there could be thousands of linked records so my approach will not work here.
I do know that probably I need to use a while loop here, something like while there is move_to_ids, then I should loop through records and keep adding IDs to list, but I just can't figure it out how to do it.
move1(stock.move ID = 10) record that has One2many relation with 2 records inside: move_to_ids (stock.move.reconcile)
each of move_to_ids has move_to_id(many2one, 'stock.move' ID = 11)
each of this move_to_id(stock.move, ID=11) records have again any number of move_to_ids (stock.move.reconcile) and each of thismove_to_idsrecords havemove_to_id('stock.move', ID=12)` and so on.
So basically I want to add to list all move_to_id IDs 10, 11, 12, etc. to list for all related move_to_ids.
moves_to_recalculate = [10,11,12] and so on until when there is 0 move_to_ids to get move_to_id from.
class StockMove(models.Model):
_name = 'stock.move'
move_to_ids = fields.One2many(
'stock.move.reconcile', 'move_from_id', string='Move to')
move_from_ids = fields.One2many(
'stock.move.reconcile', 'move_to_id', string='Move From'
)
class StockMoveReconcile(models.Model):
_name = 'stock.move.reconcile'
_description = 'Stock Move Reconcile'
move_to_id = fields.Many2one('stock.move', string='Move To')
move_from_id = fields.Many2one('stock.move', string='Move From')
def recalculate(self):
moves = self.browse(('active_ids'))
moves_to_recalculate = []
for move1 in moves:
#I add my first move in chain to list
moves_to_recalculate.append(move1.id)
#First move have 2 moves_to_ids so i make another loop to add it ID to list
for second_tier_move in move.move_to_ids:
moves_to_recalculate.appen(second_tier_move.move_to_id.id)
# secont tier move has 1 move_to_ids so i do another loop, and add it's ID to list.
for third_tier_move in second_tier_move.move_to_ids:
moves_to_recalculate.appen(third_tier_move.move_to_id.id)
#third_tier_move has another move_to_ids , and so on.
I got answer from other resource but I think i need to post it here because the answer is excellent.
def recalculate_fifo(self):
moves = self.browse(self._context.get('active_ids'))
moves_to_recalculate = moves
current_moves = moves
while current_moves:
current_moves = current_moves.mapped('move_to_ids.move_to_id')
current_moves -= moves_to_recalculate
moves_to_recalculate |= current_moves
I have defined a computed field with compute method in odoo 10 and now i want to get its value in search orm but its value remain False, and when I tried store=True its value not being changed.
if anyone has solution please let me know, I'll highly thankful.
My code is:
balance_amount = fields.Float(string="Balance Amount", compute='_compute_loan_amount')
#api.one
def _compute_loan_amount(self):
total_paid = 0.0
for loan in self:
for line in loan.loan_lines:
if line.paid:
total_paid += line.amount
balance_amount = loan.loan_amount - total_paid
self.total_amount = loan.loan_amount
self.balance_amount = balance_amount
self.total_paid_amount = total_paid
when i use search_countbelow:
loan_count = self.env['hr.loan'].search_count([('employee_id', '=', values['employee_id']), ('state', '=', 'approve'),
('balance_amount', '!=', 0)])
it always get count value even balance_amount equals to Zero
There are some things you have to do here.
Define recomputation dependencies and either use #api.multi and a for loop over self or use api.one and skip a for loop. If i understand your compute methode correct:
#api.multi
#api.depends('loan_lines.paid', 'loan_lines.amount', 'loan_amount')
def _compute_loan_amount(self):
for loan in self:
total_paid = 0.0
for line in loan.loan_lines:
if line.paid:
total_paid += line.amount
balance_amount = loan.loan_amount - total_paid
loan.total_amount = loan.loan_amount # ???
loan.balance_amount = balance_amount
loan.total_paid_amount = total_paid
Try to use a float rounding with e.g. 2 decimals, because floats can produce values like 0.000000000000000002 and that would break your search.
You either have to store the value or have to define a search method. Second approach is more difficult (in my experience).
I'm try read all name from res.partner but always console return empty res.partner()
In database I have record where is company_id = 1
#api.multi
def test(self):
my_ids = self.env['res.partner'].search([('company_id','=','1')])
print(my_ids)