From 86f9bb8f567901af43b807954d47a54274c391b3 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Mon, 30 Jun 2025 15:30:39 -0300 Subject: [PATCH 01/16] [IMP] fix layer values --- stock_currency_valuation/__manifest__.py | 2 + .../security/ir.model.access.csv | 3 + stock_currency_valuation/wizard/__init__.py | 1 + .../wizard/stock_valuation_layer_recompute.py | 171 ++++++++++++++++++ .../stock_valuation_layer_recompute.xml | 56 ++++++ ...tock_valuation_layer_revaluation_views.xml | 2 +- 6 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 stock_currency_valuation/security/ir.model.access.csv create mode 100644 stock_currency_valuation/wizard/stock_valuation_layer_recompute.py create mode 100644 stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml diff --git a/stock_currency_valuation/__manifest__.py b/stock_currency_valuation/__manifest__.py index 180a35300..45b5cc4e3 100644 --- a/stock_currency_valuation/__manifest__.py +++ b/stock_currency_valuation/__manifest__.py @@ -14,12 +14,14 @@ 'product_replenishment_cost', ], 'data': [ + 'security/ir.model.access.csv', 'views/product_category.xml', 'views/stock_picking.xml', 'views/stock_landed_cost_views.xml', 'views/product.xml', 'views/stock_valuation_layer.xml', 'wizard/stock_valuation_layer_revaluation_views.xml', + 'wizard/stock_valuation_layer_recompute.xml', ], 'installable': True, 'auto_install': False, diff --git a/stock_currency_valuation/security/ir.model.access.csv b/stock_currency_valuation/security/ir.model.access.csv new file mode 100644 index 000000000..687592cae --- /dev/null +++ b/stock_currency_valuation/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +stock_currency_valuation.access_stock_valuation_layer_recompute,access_stock_valuation_layer_recompute,stock_currency_valuation.model_stock_valuation_layer_recompute,base.group_user,1,1,1,1 +stock_currency_valuation.access_stock_valuation_layer_recompute_line,access_stock_valuation_layer_recompute_line,stock_currency_valuation.model_stock_valuation_layer_recompute_line,base.group_user,1,1,1,1 diff --git a/stock_currency_valuation/wizard/__init__.py b/stock_currency_valuation/wizard/__init__.py index fc5fdb745..36a16a8e3 100644 --- a/stock_currency_valuation/wizard/__init__.py +++ b/stock_currency_valuation/wizard/__init__.py @@ -1 +1,2 @@ from . import stock_valuation_layer_revaluation +from . import stock_valuation_layer_recompute diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py new file mode 100644 index 000000000..3f3bae85e --- /dev/null +++ b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py @@ -0,0 +1,171 @@ +from odoo import Command, api, fields, models +from odoo.addons.account.models.account_move_line import AccountMoveLine +from odoo.exceptions import UserError + + +def patch_check_reconciliation(self): + return +class StockValuationLayerRecompute(models.TransientModel): + + _name = 'stock.valuation.layer.recompute' + _description = "layer recompute" + + + company_id = fields.Many2one('res.company', default=lambda self: self.env.company) + currency_id = fields.Many2one('res.currency', related='company_id.currency_id') + product_id = fields.Many2one('product.product', string='Product') + valuation_currency_id = fields.Many2one( + 'res.currency', + string='Secondary Currency Valuation', + compute="_compute_valuation_currency_id" + ) + initial_amount_in_currency = fields.Monetary() + final_amount_in_currency = fields.Monetary() + line_ids = fields.One2many( + comodel_name='stock.valuation.layer.recompute.line', + inverse_name='recompute_id', + ) + last_manual_svl_id = fields.Many2one('stock.valuation.layer') + + @api.onchange('product_id', 'company_id') + def _onchange_product_id(self): + self.line_ids = False + self.final_amount_in_currency = False + + @api.depends('product_id', 'company_id') + def _compute_valuation_currency_id(self): + for rec in self: + product_id = rec.product_id.with_company(rec.company_id) + rec.valuation_currency_id = product_id.categ_id.valuation_currency_id + + def action_compute_lines(self): + + last_manual_svl_id = self.env['stock.valuation.layer'].search( + [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'like', 'Manual%')] + , order="create_date desc", limit=1) + self.last_manual_svl_id = last_manual_svl_id + + leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] + if last_manual_svl_id: + leaf += [('id', '>', last_manual_svl_id.id)] + + svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") + lines = [Command.clear()] + quantity_at_time = 0 + standard_price_in_currency = self.initial_amount_in_currency + + for svl_id in svl_ids: + svl_type = '' + vals = {'layer_id': svl_id.id} + quantity_at_time = quantity_at_time + svl_id.quantity + + if svl_id.stock_move_id and (svl_id.stock_move_id._is_out() or svl_id.stock_move_id.is_inventory): + # Si el movimento es de salida o de inventario, valor es el registrado en el producto + standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency + new_unit_cost_in_currency = standard_price_in_currency + new_value_in_currency = standard_price_in_currency * svl_id.quantity + svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' + + # es un ajuste? + elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): + new_value_in_currency = svl_id.value_in_currency + new_unit_cost_in_currency = svl_id.unit_cost_in_currency + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'ajustement' + + elif svl_id.stock_move_id and svl_id.stock_move_id._is_returned(valued_type='in'): + # Si es una devolucion y existe el movimiento de origen + # el valor de avco sale del mov de origen sino sale de producto + + if svl_id.stock_move_id.origin_returned_move_id: + for temp_vals in lines: + if temp_vals[2] and temp_vals[2]['layer_id'] in svl_id.stock_move_id.origin_returned_move_id.stock_valuation_layer_ids.ids: + new_value_in_currency = temp_vals[2]['new_unit_cost_in_currency'] * svl_id.quantity + new_unit_cost_in_currency = temp_vals[2]['new_unit_cost_in_currency'] + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'return of %s ' % temp_vals[2]['layer_id'] + + break + else: + new_value_in_currency = standard_price_in_currency * svl_id.quantity + new_unit_cost_in_currency = standard_price_in_currency + svl_type = 'ret_without_move' + + elif svl_id.manual_currency_rate: + new_value_in_currency = svl_id.value * svl_id.manual_currency_rate + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'manual currency rate %s' % svl_id.manual_currency_rate + else: + new_value_in_currency = svl_id.currency_id._convert( + from_amount=svl_id.value, + to_currency=svl_id.valuation_currency_id, + company=svl_id.company_id, + date=svl_id.create_date, + ) + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'slv' + + vals['new_value_in_currency'] = new_value_in_currency + vals['new_unit_cost_in_currency'] = new_unit_cost_in_currency + vals['standard_price_in_currency'] = standard_price_in_currency + vals['quantity_at_time'] = quantity_at_time + vals['svl_type'] = svl_type + + need_change_1 = self.valuation_currency_id.compare_amounts(svl_id.value_in_currency, new_value_in_currency) != 0.0 + need_change_2 = self.valuation_currency_id.compare_amounts(svl_id.unit_cost_in_currency, new_unit_cost_in_currency) != 0.0 + + vals['need_changes'] = True if need_change_1 or need_change_2 else False + lines.append(Command.create(vals),) + self.line_ids = lines + self.final_amount_in_currency = standard_price_in_currency + + def action_manual_slv_revaluation(self): + orig_check_reconciliation = AccountMoveLine._check_reconciliation + AccountMoveLine._check_reconciliation = patch_check_reconciliation + + for line_id in self.line_ids.filtered('need_changes'): + if line_id.layer_id.stock_landed_cost_id: + raise UserError('No puedo ajustar un landed cost') + line_id.layer_id.write({ + 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, + 'value_in_currency':line_id.new_value_in_currency + }) + lines = [] + for move_line in line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id): + multiplier = 1 if move_line.amount_currency >= 0 else -1 + lines.append(Command.update(move_line.id,{'amount_currency': line_id.new_value_in_currency * multiplier})) + if lines: + line_id.layer_id.account_move_id.line_ids = lines + + self.product_id.with_company(self.company_id.id).with_context( + disable_auto_svl=True + ).sudo().write({'standard_price_in_currency': self.final_amount_in_currency}) + AccountMoveLine._check_reconciliation = orig_check_reconciliation + + +class StockValuationLayerRecomputeLine(models.TransientModel): + + _name = 'stock.valuation.layer.recompute.line' + _description = "lines layer recompute" + + + + #layer_unit_cost = fields.Monetary('Unit Value in currency', compute="_compute_other_currency_values", currency_field='valuation_currency_id', store=True) + #layer_value = fields.Monetary('Total Value incurrency', compute="_compute_other_currency_values", currency_field='valuation_currency_id', store=True) + + layer_id = fields.Many2one('stock.valuation.layer') + quantity = fields.Float(related="layer_id.quantity") + quantity_at_time = fields.Float() + layer_date = fields.Datetime(related="layer_id.create_date") + recompute_id = fields.Many2one('stock.valuation.layer.recompute') + currency_id = fields.Many2one('res.currency', related='recompute_id.valuation_currency_id') + layer_unit_cost_in_currency = fields.Monetary(related="layer_id.unit_cost_in_currency") + layer_value_in_currency = fields.Monetary(related="layer_id.value_in_currency") + new_unit_cost_in_currency = fields.Monetary() + new_value_in_currency = fields.Monetary() + standard_price_in_currency = fields.Monetary() + need_changes = fields.Boolean() + svl_type = fields.Char() diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml new file mode 100644 index 000000000..0b65f4c7a --- /dev/null +++ b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml @@ -0,0 +1,56 @@ + + + + + stock.valuation.layer.recompute.form + stock.valuation.layer.recompute + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + Recompute layer + ir.actions.act_window + stock.valuation.layer.recompute + form + + + + +
diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_revaluation_views.xml b/stock_currency_valuation/wizard/stock_valuation_layer_revaluation_views.xml index a0776b840..9061fcc74 100644 --- a/stock_currency_valuation/wizard/stock_valuation_layer_revaluation_views.xml +++ b/stock_currency_valuation/wizard/stock_valuation_layer_revaluation_views.xml @@ -11,7 +11,7 @@
= ( by ) Use a negative added value to record a decrease in the product value -
+ From ebabf5af33d3a736606e7128f7633681181fd786 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Wed, 2 Jul 2025 10:28:57 -0300 Subject: [PATCH 02/16] [IMP] more fixes --- .../wizard/stock_valuation_layer_recompute.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py index 3f3bae85e..3bc9d7414 100644 --- a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py @@ -5,7 +5,16 @@ def patch_check_reconciliation(self): return -class StockValuationLayerRecompute(models.TransientModel): +# Todo - agregar estado +# -1 draft solo modifico producto +# 2 in_process cuando apreto action_compute_lines se computan las lineas y se pone es ente estado (puedoapretar mas de una vz ) +# el boton action_compute_lines se ve en draft u en process +# 3 done no dear moficar +# 4 cancel +# action_manual_slv_revaluation pasa a done +# metodo que pase cancel +# vista de lista al menu +class StockValuationLayerRecompute(models.model): _name = 'stock.valuation.layer.recompute' _description = "layer recompute" @@ -41,14 +50,11 @@ def _compute_valuation_currency_id(self): def action_compute_lines(self): last_manual_svl_id = self.env['stock.valuation.layer'].search( - [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'like', 'Manual%')] + [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] , order="create_date desc", limit=1) self.last_manual_svl_id = last_manual_svl_id leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] - if last_manual_svl_id: - leaf += [('id', '>', last_manual_svl_id.id)] - svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") lines = [Command.clear()] quantity_at_time = 0 @@ -67,7 +73,8 @@ def action_compute_lines(self): svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' # es un ajuste? - elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): + #elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): + elif not svl_id.stock_move_id: new_value_in_currency = svl_id.value_in_currency new_unit_cost_in_currency = svl_id.unit_cost_in_currency standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency @@ -116,8 +123,8 @@ def action_compute_lines(self): need_change_1 = self.valuation_currency_id.compare_amounts(svl_id.value_in_currency, new_value_in_currency) != 0.0 need_change_2 = self.valuation_currency_id.compare_amounts(svl_id.unit_cost_in_currency, new_unit_cost_in_currency) != 0.0 - - vals['need_changes'] = True if need_change_1 or need_change_2 else False + need_change_3 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id + vals['need_changes'] = True if (need_change_1 or need_change_2) and need_change_3 else False lines.append(Command.create(vals),) self.line_ids = lines self.final_amount_in_currency = standard_price_in_currency @@ -146,7 +153,7 @@ def action_manual_slv_revaluation(self): AccountMoveLine._check_reconciliation = orig_check_reconciliation -class StockValuationLayerRecomputeLine(models.TransientModel): +class StockValuationLayerRecomputeLine(models.model): _name = 'stock.valuation.layer.recompute.line' _description = "lines layer recompute" From 7407ae302e00db3bae11fe48b010f8a4a5888f3e Mon Sep 17 00:00:00 2001 From: Felipe Garcia Suez Date: Wed, 2 Jul 2025 12:07:15 -0300 Subject: [PATCH 03/16] [IMP] stock_currency_valuation: Reorganize stock valuation layer recompute logic to model --- stock_currency_valuation/__manifest__.py | 2 +- stock_currency_valuation/models/__init__.py | 1 + .../models/stock_valuation_layer_recompute.py | 337 ++++++++++++++++++ .../views/stock_valuation_layer_recompute.xml | 88 +++++ stock_currency_valuation/wizard/__init__.py | 1 - .../wizard/stock_valuation_layer_recompute.py | 178 --------- .../stock_valuation_layer_recompute.xml | 56 --- stock_ux/models/stock_move.py | 4 +- 8 files changed, 429 insertions(+), 238 deletions(-) create mode 100644 stock_currency_valuation/models/stock_valuation_layer_recompute.py create mode 100644 stock_currency_valuation/views/stock_valuation_layer_recompute.xml delete mode 100644 stock_currency_valuation/wizard/stock_valuation_layer_recompute.py delete mode 100644 stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml diff --git a/stock_currency_valuation/__manifest__.py b/stock_currency_valuation/__manifest__.py index 45b5cc4e3..20fc19459 100644 --- a/stock_currency_valuation/__manifest__.py +++ b/stock_currency_valuation/__manifest__.py @@ -20,8 +20,8 @@ 'views/stock_landed_cost_views.xml', 'views/product.xml', 'views/stock_valuation_layer.xml', + 'views/stock_valuation_layer_recompute.xml', 'wizard/stock_valuation_layer_revaluation_views.xml', - 'wizard/stock_valuation_layer_recompute.xml', ], 'installable': True, 'auto_install': False, diff --git a/stock_currency_valuation/models/__init__.py b/stock_currency_valuation/models/__init__.py index f9cbb91a7..cfdd906b8 100644 --- a/stock_currency_valuation/models/__init__.py +++ b/stock_currency_valuation/models/__init__.py @@ -7,3 +7,4 @@ from . import account_move from . import stock_picking from . import stock_move_line +from . import stock_valuation_layer_recompute diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py new file mode 100644 index 000000000..0fb103d97 --- /dev/null +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -0,0 +1,337 @@ +from odoo import Command, api, fields, models +from odoo.addons.account.models.account_move_line import AccountMoveLine +from odoo.exceptions import UserError + + +def patch_check_reconciliation(self): + return +class StockValuationLayerRecompute(models.Model): + + _name = 'stock.valuation.layer.recompute' + _description = "layer recompute" + + + company_id = fields.Many2one('res.company', default=lambda self: self.env.company) + currency_id = fields.Many2one('res.currency', related='company_id.currency_id') + product_id = fields.Many2one( + 'product.product', + string='Product', + readonly=False + ) + valuation_currency_id = fields.Many2one( + 'res.currency', + string='Secondary Currency Valuation', + compute="_compute_valuation_currency_id" + ) + initial_amount = fields.Monetary() + final_amount = fields.Monetary() + initial_amount_in_currency = fields.Monetary() + final_amount_in_currency = fields.Monetary() + line_ids = fields.One2many( + comodel_name='stock.valuation.layer.recompute.line', + inverse_name='recompute_id', + ) + last_manual_svl_id = fields.Many2one('stock.valuation.layer') + amount_changed = fields.Boolean() + slv_changed = fields.Boolean() + + state = fields.Selection([ + ('draft', 'Draft'), + ('in_process', 'In Process'), + ('done', 'Done'), + ('no_change', 'Not changes Required'), + ('cancel', 'Cancelled') + ], default='draft', string='Status', required=True, readonly=True, copy=False) + + @api.onchange('product_id', 'company_id') + def _onchange_product_id(self): + self.line_ids = False + self.final_amount_in_currency = False + + @api.depends('product_id', 'company_id') + def _compute_valuation_currency_id(self): + for rec in self: + product_id = rec.product_id.with_company(rec.company_id) + rec.valuation_currency_id = product_id.categ_id.valuation_currency_id + + def action_cancel(self): + for rec in self: + rec.state = 'cancel' + + def back_to_draft(self): + for rec in self: + rec.state = 'draft' + + def delete_adjust_compute_lines(self): + self.env['stock.valuation.layer'].search( + [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] + , order="create_date desc").sudo().unlink() + self.action_compute_lines() + + def action_compute_lines(self): + + # last_manual_svl_id = self.env['stock.valuation.layer'].search( + # [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] + # , order="create_date desc", limit=1) + # self.last_manual_svl_id = last_manual_svl_id + + self.last_manual_svl_id = False + leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] + svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") + lines = [Command.clear()] + quantity_at_time = 0 + standard_price_in_currency = 0 + standard_price = 0 + + self.initial_amount_in_currency = self.product_id.with_company(self.company_id.id).standard_price_in_currency + self.initial_amount = self.product_id.with_company(self.company_id.id).standard_price + for svl_id in svl_ids: + svl_type = '' + vals = { + 'layer_id': svl_id.id, + 'layer_unit_cost': svl_id.unit_cost, + 'layer_value': svl_id.value, + 'layer_unit_cost_in_currency': svl_id.unit_cost_in_currency, + 'layer_value_in_currency': svl_id.value_in_currency, + } + quantity_at_time = quantity_at_time + svl_id.quantity + + if svl_id.stock_move_id and (svl_id.stock_move_id._is_out() or svl_id.stock_move_id.is_inventory): + # Si el movimento es de salida o de inventario, valor es el registrado en el producto + standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency + standard_price = standard_price if standard_price else svl_id.unit_cost + + new_unit_cost = standard_price + new_value = standard_price * svl_id.quantity + + new_unit_cost_in_currency = standard_price_in_currency + new_value_in_currency = standard_price_in_currency * svl_id.quantity + + svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' + + # es un ajuste? + #elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): + elif not svl_id.stock_move_id: + new_value_in_currency = svl_id.value_in_currency + new_unit_cost_in_currency = svl_id.unit_cost_in_currency + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + + new_value = svl_id.value + new_unit_cost = svl_id.unit_cost + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + svl_type = 'ajustement' + + elif svl_id.stock_move_id and svl_id.stock_move_id._is_returned(valued_type='in'): + # Si es una devolucion y existe el movimiento de origen + # el valor de avco sale del mov de origen sino sale de producto + + if svl_id.stock_move_id.origin_returned_move_id: + for temp_vals in lines: + if temp_vals[2] and temp_vals[2]['layer_id'] in svl_id.stock_move_id.origin_returned_move_id.stock_valuation_layer_ids.ids: + new_value_in_currency = temp_vals[2]['new_unit_cost_in_currency'] * svl_id.quantity + new_unit_cost_in_currency = temp_vals[2]['new_unit_cost_in_currency'] + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + new_value = temp_vals[2]['new_unit_cost'] * svl_id.quantity + new_unit_cost = temp_vals[2]['new_unit_cost'] + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + svl_type = 'return of %s ' % temp_vals[2]['layer_id'] + + break + else: + new_value_in_currency = standard_price_in_currency * svl_id.quantity + new_unit_cost_in_currency = standard_price_in_currency + new_value = standard_price * svl_id.quantity + new_unit_cost = standard_price + + svl_type = 'ret_without_move' + + elif svl_id.manual_currency_rate: + # caso viene de un landed cost con manual currency rate + if svl_id.stock_landed_cost_id.inverse_currency_rate: + + new_value = svl_id.value + new_unit_cost = svl_id.unit_cost + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + new_value_in_currency = svl_id.value * svl_id.manual_currency_rate + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + + svl_type = 'landed manual rate %s' % svl_id.manual_currency_rate + # caso viene de una compra con manual currency rate + elif svl_id.stock_move_id.picking_id.currency_rate and svl_id.stock_move_id.purchase_line_id.order_id.currency_id == svl_id.stock_move_id.picking_id.valuation_currency_id: + price_unit = svl_id.stock_move_id.purchase_line_id.price_unit / svl_id.stock_move_id.picking_id.currency_rate + + new_value_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit * svl_id.quantity + new_unit_cost_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + + + new_value = price_unit * svl_id.quantity + new_unit_cost = price_unit + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + # Otros casos ? + svl_type = 'purchase manual rate %s' % svl_id.manual_currency_rate + else: + new_value = svl_id.value + new_unit_cost = svl_id.unit_cost + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + new_value_in_currency = svl_id.value * svl_id.manual_currency_rate + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + + svl_type = 'manual currency rate %s' % svl_id.manual_currency_rate + else: + if svl_id.stock_landed_cost_id.valuation_currency_id: + new_value_in_currency = svl_id.currency_id._convert( + from_amount=svl_id.value, + to_currency=svl_id.valuation_currency_id, + company=svl_id.company_id, + date=svl_id.create_date, + ) + new_value = svl_id.value + new_unit_cost = svl_id.unit_cost + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'slv' + + elif svl_id.stock_move_id.picking_id.valuation_currency_id and svl_id.stock_move_id.purchase_line_id.order_id.currency_id == svl_id.stock_move_id.picking_id.valuation_currency_id: + + new_value = svl_id.valuation_currency_id._convert( + from_amount=svl_id.value_in_currency, + to_currency=svl_id.currency_id, + company=svl_id.company_id, + date=svl_id.create_date, + ) + + new_value_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit * svl_id.quantity + new_unit_cost_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + + + new_value = new_value + new_unit_cost = new_value / svl_id.quantity if svl_id.quantity else 0 + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + svl_type = 'slv' + else: + new_value_in_currency = svl_id.currency_id._convert( + from_amount=svl_id.value, + to_currency=svl_id.valuation_currency_id, + company=svl_id.company_id, + date=svl_id.create_date, + ) + new_value = svl_id.value + new_unit_cost = svl_id.unit_cost + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + svl_type = 'slv' + + vals['new_value'] = new_value + vals['new_unit_cost'] = new_unit_cost + vals['standard_price'] = standard_price + + vals['new_value_in_currency'] = new_value_in_currency + vals['new_unit_cost_in_currency'] = new_unit_cost_in_currency + vals['standard_price_in_currency'] = standard_price_in_currency + vals['quantity_at_time'] = quantity_at_time + vals['svl_type'] = svl_type + + need_change_1 = self.valuation_currency_id.compare_amounts(svl_id.value_in_currency, new_value_in_currency) != 0.0 + need_change_2 = self.valuation_currency_id.compare_amounts(svl_id.unit_cost_in_currency, new_unit_cost_in_currency) != 0.0 + need_change_3 = self.currency_id.compare_amounts(svl_id.value, new_value) != 0.0 + need_change_4 = self.currency_id.compare_amounts(svl_id.unit_cost, new_unit_cost) != 0.0 + + #need_change_5 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id + need_change_5 = True + vals['need_changes'] = True if (need_change_1 or need_change_2 or need_change_3 or need_change_4) and need_change_5 else False + lines.append(Command.create(vals),) + self.line_ids = lines + self.final_amount_in_currency = standard_price_in_currency + self.final_amount = standard_price + self.state = 'in_process' + self.action_check_need_changes() + + def action_check_need_changes(self): + if not self.line_ids.filtered('need_changes') and \ + self.final_amount_in_currency == self.initial_amount_in_currency or \ + self.final_amount == self.initial_amount: + self.state = 'no_change' + + def action_manual_slv_revaluation(self): + orig_check_reconciliation = AccountMoveLine._check_reconciliation + AccountMoveLine._check_reconciliation = patch_check_reconciliation + slv_changed = False + + for line_id in self.line_ids.filtered('need_changes'): + slv_changed = True + if line_id.layer_id.stock_landed_cost_id: + raise UserError('No puedo ajustar un landed cost') + line_id.layer_id.write({ + 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, + 'value_in_currency':line_id.new_value_in_currency, + 'unit_cost': line_id.new_unit_cost_in_currency, + 'value':line_id.new_value_in_currency + }) + lines = [] + for move_line in line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id): + multiplier = 1 if move_line.amount_currency >= 0 else -1 + field = 'debit' if move_line.credit == 0 else 'credit' + lines.append(Command.update(move_line.id,{ + 'amount_currency': line_id.new_value_in_currency * multiplier, + field: line_id.new_value, + })) + if lines: + line_id.layer_id.account_move_id.line_ids = lines + + if self.product_id.with_company(self.company_id.id).standard_price_in_currency != self.final_amount_in_currency: + self.product_id.with_company(self.company_id.id).with_context( + disable_auto_svl=True + ).sudo().write({'standard_price_in_currency': self.final_amount_in_currency}) + self.amount_changed = True + if self.product_id.with_company(self.company_id.id).standard_price != self.final_amount: + self.product_id.with_company(self.company_id.id).with_context( + disable_auto_svl=True + ).sudo().write({'standard_price': self.final_amount}) + self.amount_changed = True + + self.slv_changed = slv_changed + AccountMoveLine._check_reconciliation = orig_check_reconciliation + self.state = 'done' + + +class StockValuationLayerRecomputeLine(models.Model): + + _name = 'stock.valuation.layer.recompute.line' + _description = "lines layer recompute" + + + layer_id = fields.Many2one('stock.valuation.layer') + quantity = fields.Float(related="layer_id.quantity") + quantity_at_time = fields.Float() + layer_date = fields.Datetime(related="layer_id.create_date") + recompute_id = fields.Many2one('stock.valuation.layer.recompute') + currency_id = fields.Many2one('res.currency', related='recompute_id.valuation_currency_id') + company_currency_id = fields.Many2one('res.currency', related='recompute_id.currency_id') + + # company currency + layer_unit_cost = fields.Monetary(currency_field="company_currency_id") + layer_value = fields.Monetary(currency_field="company_currency_id") + new_unit_cost = fields.Monetary(currency_field="company_currency_id") + new_value = fields.Monetary(currency_field="company_currency_id") + standard_price = fields.Monetary(currency_field="company_currency_id") + + # Secundary currency + layer_unit_cost_in_currency = fields.Monetary() + layer_value_in_currency = fields.Monetary() + new_unit_cost_in_currency = fields.Monetary() + new_value_in_currency = fields.Monetary() + standard_price_in_currency = fields.Monetary() + need_changes = fields.Boolean() + svl_type = fields.Char() diff --git a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml new file mode 100644 index 000000000..bba2f8811 --- /dev/null +++ b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml @@ -0,0 +1,88 @@ + + + + stock.valuation.layer.recompute.form + stock.valuation.layer.recompute + form + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + stock.valuation.layer.recompute.list + stock.valuation.layer.recompute + tree + + + + + + + + + + + + + + + + Recompute layer + ir.actions.act_window + stock.valuation.layer.recompute + tree,form + + + + +
diff --git a/stock_currency_valuation/wizard/__init__.py b/stock_currency_valuation/wizard/__init__.py index 36a16a8e3..fc5fdb745 100644 --- a/stock_currency_valuation/wizard/__init__.py +++ b/stock_currency_valuation/wizard/__init__.py @@ -1,2 +1 @@ from . import stock_valuation_layer_revaluation -from . import stock_valuation_layer_recompute diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py deleted file mode 100644 index 3bc9d7414..000000000 --- a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.py +++ /dev/null @@ -1,178 +0,0 @@ -from odoo import Command, api, fields, models -from odoo.addons.account.models.account_move_line import AccountMoveLine -from odoo.exceptions import UserError - - -def patch_check_reconciliation(self): - return -# Todo - agregar estado -# -1 draft solo modifico producto -# 2 in_process cuando apreto action_compute_lines se computan las lineas y se pone es ente estado (puedoapretar mas de una vz ) -# el boton action_compute_lines se ve en draft u en process -# 3 done no dear moficar -# 4 cancel -# action_manual_slv_revaluation pasa a done -# metodo que pase cancel -# vista de lista al menu -class StockValuationLayerRecompute(models.model): - - _name = 'stock.valuation.layer.recompute' - _description = "layer recompute" - - - company_id = fields.Many2one('res.company', default=lambda self: self.env.company) - currency_id = fields.Many2one('res.currency', related='company_id.currency_id') - product_id = fields.Many2one('product.product', string='Product') - valuation_currency_id = fields.Many2one( - 'res.currency', - string='Secondary Currency Valuation', - compute="_compute_valuation_currency_id" - ) - initial_amount_in_currency = fields.Monetary() - final_amount_in_currency = fields.Monetary() - line_ids = fields.One2many( - comodel_name='stock.valuation.layer.recompute.line', - inverse_name='recompute_id', - ) - last_manual_svl_id = fields.Many2one('stock.valuation.layer') - - @api.onchange('product_id', 'company_id') - def _onchange_product_id(self): - self.line_ids = False - self.final_amount_in_currency = False - - @api.depends('product_id', 'company_id') - def _compute_valuation_currency_id(self): - for rec in self: - product_id = rec.product_id.with_company(rec.company_id) - rec.valuation_currency_id = product_id.categ_id.valuation_currency_id - - def action_compute_lines(self): - - last_manual_svl_id = self.env['stock.valuation.layer'].search( - [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] - , order="create_date desc", limit=1) - self.last_manual_svl_id = last_manual_svl_id - - leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] - svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") - lines = [Command.clear()] - quantity_at_time = 0 - standard_price_in_currency = self.initial_amount_in_currency - - for svl_id in svl_ids: - svl_type = '' - vals = {'layer_id': svl_id.id} - quantity_at_time = quantity_at_time + svl_id.quantity - - if svl_id.stock_move_id and (svl_id.stock_move_id._is_out() or svl_id.stock_move_id.is_inventory): - # Si el movimento es de salida o de inventario, valor es el registrado en el producto - standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency - new_unit_cost_in_currency = standard_price_in_currency - new_value_in_currency = standard_price_in_currency * svl_id.quantity - svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' - - # es un ajuste? - #elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): - elif not svl_id.stock_move_id: - new_value_in_currency = svl_id.value_in_currency - new_unit_cost_in_currency = svl_id.unit_cost_in_currency - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'ajustement' - - elif svl_id.stock_move_id and svl_id.stock_move_id._is_returned(valued_type='in'): - # Si es una devolucion y existe el movimiento de origen - # el valor de avco sale del mov de origen sino sale de producto - - if svl_id.stock_move_id.origin_returned_move_id: - for temp_vals in lines: - if temp_vals[2] and temp_vals[2]['layer_id'] in svl_id.stock_move_id.origin_returned_move_id.stock_valuation_layer_ids.ids: - new_value_in_currency = temp_vals[2]['new_unit_cost_in_currency'] * svl_id.quantity - new_unit_cost_in_currency = temp_vals[2]['new_unit_cost_in_currency'] - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'return of %s ' % temp_vals[2]['layer_id'] - - break - else: - new_value_in_currency = standard_price_in_currency * svl_id.quantity - new_unit_cost_in_currency = standard_price_in_currency - svl_type = 'ret_without_move' - - elif svl_id.manual_currency_rate: - new_value_in_currency = svl_id.value * svl_id.manual_currency_rate - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'manual currency rate %s' % svl_id.manual_currency_rate - else: - new_value_in_currency = svl_id.currency_id._convert( - from_amount=svl_id.value, - to_currency=svl_id.valuation_currency_id, - company=svl_id.company_id, - date=svl_id.create_date, - ) - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'slv' - - vals['new_value_in_currency'] = new_value_in_currency - vals['new_unit_cost_in_currency'] = new_unit_cost_in_currency - vals['standard_price_in_currency'] = standard_price_in_currency - vals['quantity_at_time'] = quantity_at_time - vals['svl_type'] = svl_type - - need_change_1 = self.valuation_currency_id.compare_amounts(svl_id.value_in_currency, new_value_in_currency) != 0.0 - need_change_2 = self.valuation_currency_id.compare_amounts(svl_id.unit_cost_in_currency, new_unit_cost_in_currency) != 0.0 - need_change_3 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id - vals['need_changes'] = True if (need_change_1 or need_change_2) and need_change_3 else False - lines.append(Command.create(vals),) - self.line_ids = lines - self.final_amount_in_currency = standard_price_in_currency - - def action_manual_slv_revaluation(self): - orig_check_reconciliation = AccountMoveLine._check_reconciliation - AccountMoveLine._check_reconciliation = patch_check_reconciliation - - for line_id in self.line_ids.filtered('need_changes'): - if line_id.layer_id.stock_landed_cost_id: - raise UserError('No puedo ajustar un landed cost') - line_id.layer_id.write({ - 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, - 'value_in_currency':line_id.new_value_in_currency - }) - lines = [] - for move_line in line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id): - multiplier = 1 if move_line.amount_currency >= 0 else -1 - lines.append(Command.update(move_line.id,{'amount_currency': line_id.new_value_in_currency * multiplier})) - if lines: - line_id.layer_id.account_move_id.line_ids = lines - - self.product_id.with_company(self.company_id.id).with_context( - disable_auto_svl=True - ).sudo().write({'standard_price_in_currency': self.final_amount_in_currency}) - AccountMoveLine._check_reconciliation = orig_check_reconciliation - - -class StockValuationLayerRecomputeLine(models.model): - - _name = 'stock.valuation.layer.recompute.line' - _description = "lines layer recompute" - - - - #layer_unit_cost = fields.Monetary('Unit Value in currency', compute="_compute_other_currency_values", currency_field='valuation_currency_id', store=True) - #layer_value = fields.Monetary('Total Value incurrency', compute="_compute_other_currency_values", currency_field='valuation_currency_id', store=True) - - layer_id = fields.Many2one('stock.valuation.layer') - quantity = fields.Float(related="layer_id.quantity") - quantity_at_time = fields.Float() - layer_date = fields.Datetime(related="layer_id.create_date") - recompute_id = fields.Many2one('stock.valuation.layer.recompute') - currency_id = fields.Many2one('res.currency', related='recompute_id.valuation_currency_id') - layer_unit_cost_in_currency = fields.Monetary(related="layer_id.unit_cost_in_currency") - layer_value_in_currency = fields.Monetary(related="layer_id.value_in_currency") - new_unit_cost_in_currency = fields.Monetary() - new_value_in_currency = fields.Monetary() - standard_price_in_currency = fields.Monetary() - need_changes = fields.Boolean() - svl_type = fields.Char() diff --git a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml b/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml deleted file mode 100644 index 0b65f4c7a..000000000 --- a/stock_currency_valuation/wizard/stock_valuation_layer_recompute.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - stock.valuation.layer.recompute.form - stock.valuation.layer.recompute - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - Recompute layer - ir.actions.act_window - stock.valuation.layer.recompute - form - - - - -
diff --git a/stock_ux/models/stock_move.py b/stock_ux/models/stock_move.py index ad53d277d..3f384b589 100644 --- a/stock_ux/models/stock_move.py +++ b/stock_ux/models/stock_move.py @@ -2,7 +2,7 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import models, fields, api, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError from odoo.tools import float_compare @@ -184,7 +184,7 @@ def check_cancel(self): if self.filtered( lambda x: x.picking_id and x.state == 'cancel' and not self.user_has_groups('stock_ux.allow_picking_cancellation')): raise ValidationError("Only User with 'Picking cancelation allow' rights can cancel pickings") - + def _merge_moves(self, merge_into=False): # 22/04/2024: Agregamos esto porque sino al intentar confirmar compras con usuarios sin permisos, podia pasar que salga la constrain de arriba (check_cancel) return super(StockMove,self.with_context(cancel_from_order=True))._merge_moves(merge_into = merge_into) From 3587f2669f0c051b14af64dd5414051fb41b69aa Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Fri, 11 Jul 2025 11:28:59 -0300 Subject: [PATCH 04/16] [FIX] Set in zero when produnt dont has qutanty --- .../models/stock_valuation_layer_recompute.py | 4 ++++ .../views/stock_valuation_layer_recompute.xml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 0fb103d97..ebfcba12a 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -233,6 +233,10 @@ def action_compute_lines(self): standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency svl_type = 'slv' + if quantity_at_time == 0: + standard_price_in_currency = 0 + standard_price = 0 + vals['new_value'] = new_value vals['new_unit_cost'] = new_unit_cost vals['standard_price'] = standard_price diff --git a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml index bba2f8811..452b8c174 100644 --- a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml +++ b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml @@ -70,6 +70,8 @@ + + From 0d0a29b30b0239a364b57f2cd7e714a35b03fc8f Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Fri, 11 Jul 2025 15:56:35 -0300 Subject: [PATCH 05/16] [IMP] stock_currency_valuation: valuation --- .../models/stock_valuation_layer_recompute.py | 54 ++++++++++++------- .../views/stock_valuation_layer_recompute.xml | 6 +-- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index ebfcba12a..5303c71b8 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -1,5 +1,4 @@ from odoo import Command, api, fields, models -from odoo.addons.account.models.account_move_line import AccountMoveLine from odoo.exceptions import UserError @@ -63,19 +62,22 @@ def back_to_draft(self): rec.state = 'draft' def delete_adjust_compute_lines(self): - self.env['stock.valuation.layer'].search( - [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] - , order="create_date desc").sudo().unlink() + manual_slv = self.env['stock.valuation.layer'].search( + [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('create_uid', '=', 1), ('stock_move_id', '=', False)] + , order="create_date desc") + manual_slv.mapped('account_move_id').button_draft() + manual_slv.mapped('account_move_id').unlink() + manual_slv.unlink() + self.action_compute_lines() def action_compute_lines(self): - # last_manual_svl_id = self.env['stock.valuation.layer'].search( - # [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('description', 'ilike', 'manual%')] - # , order="create_date desc", limit=1) - # self.last_manual_svl_id = last_manual_svl_id + last_manual_svl_id = self.env['stock.valuation.layer'].search( + [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('create_uid', '=', 1), ('stock_move_id', '=', False)] + , order="create_date desc", limit=1) + self.last_manual_svl_id = last_manual_svl_id - self.last_manual_svl_id = False leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") lines = [Command.clear()] @@ -172,8 +174,8 @@ def action_compute_lines(self): new_value = price_unit * svl_id.quantity new_unit_cost = price_unit standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - # Otros casos ? svl_type = 'purchase manual rate %s' % svl_id.manual_currency_rate + # Otros casos ? else: new_value = svl_id.value new_unit_cost = svl_id.unit_cost @@ -198,7 +200,7 @@ def action_compute_lines(self): new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'slv' + svl_type = 'landed cost' elif svl_id.stock_move_id.picking_id.valuation_currency_id and svl_id.stock_move_id.purchase_line_id.order_id.currency_id == svl_id.stock_move_id.picking_id.valuation_currency_id: @@ -217,7 +219,7 @@ def action_compute_lines(self): new_value = new_value new_unit_cost = new_value / svl_id.quantity if svl_id.quantity else 0 standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - svl_type = 'slv' + svl_type = 'purchase' else: new_value_in_currency = svl_id.currency_id._convert( from_amount=svl_id.value, @@ -233,6 +235,7 @@ def action_compute_lines(self): standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency svl_type = 'slv' + # Si no queda producto el precio es 0 if quantity_at_time == 0: standard_price_in_currency = 0 standard_price = 0 @@ -252,8 +255,7 @@ def action_compute_lines(self): need_change_3 = self.currency_id.compare_amounts(svl_id.value, new_value) != 0.0 need_change_4 = self.currency_id.compare_amounts(svl_id.unit_cost, new_unit_cost) != 0.0 - #need_change_5 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id - need_change_5 = True + need_change_5 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id vals['need_changes'] = True if (need_change_1 or need_change_2 or need_change_3 or need_change_4) and need_change_5 else False lines.append(Command.create(vals),) self.line_ids = lines @@ -264,15 +266,16 @@ def action_compute_lines(self): def action_check_need_changes(self): if not self.line_ids.filtered('need_changes') and \ - self.final_amount_in_currency == self.initial_amount_in_currency or \ + self.final_amount_in_currency == self.initial_amount_in_currency and \ self.final_amount == self.initial_amount: self.state = 'no_change' def action_manual_slv_revaluation(self): - orig_check_reconciliation = AccountMoveLine._check_reconciliation - AccountMoveLine._check_reconciliation = patch_check_reconciliation + #orig_check_reconciliation = AccountMoveLine._check_reconciliation + #AccountMoveLine._check_reconciliation = patch_check_reconciliation slv_changed = False - + # to_reconciled_line_ids guarda todas las conciliaciones + to_reconciled_line_ids = [] for line_id in self.line_ids.filtered('need_changes'): slv_changed = True if line_id.layer_id.stock_landed_cost_id: @@ -284,7 +287,12 @@ def action_manual_slv_revaluation(self): 'value':line_id.new_value_in_currency }) lines = [] - for move_line in line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id): + product_move_line_ids = line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id) + #agrego las full reconiliaciones + to_reconciled_line_ids.append(product_move_line_ids.full_reconcile_id.reconciled_line_ids) + move_ids = product_move_line_ids.mapped('move_id') + move_ids.button_draft() + for move_line in product_move_line_ids: multiplier = 1 if move_line.amount_currency >= 0 else -1 field = 'debit' if move_line.credit == 0 else 'credit' lines.append(Command.update(move_line.id,{ @@ -293,6 +301,7 @@ def action_manual_slv_revaluation(self): })) if lines: line_id.layer_id.account_move_id.line_ids = lines + move_ids.action_post() if self.product_id.with_company(self.company_id.id).standard_price_in_currency != self.final_amount_in_currency: self.product_id.with_company(self.company_id.id).with_context( @@ -306,7 +315,12 @@ def action_manual_slv_revaluation(self): self.amount_changed = True self.slv_changed = slv_changed - AccountMoveLine._check_reconciliation = orig_check_reconciliation + for to_reconciled_lines in to_reconciled_line_ids: + # si no tiene reconciliaciones, lo reconcilio sino supongo + # que ya lo reconcilie en antes + if not any(to_reconciled_lines.mapped('reconciled')): + to_reconciled_lines.reconcile() + #AccountMoveLine._check_reconciliation = orig_check_reconciliation self.state = 'done' diff --git a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml index 452b8c174..a1b3d82d3 100644 --- a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml +++ b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml @@ -29,7 +29,7 @@ - + @@ -68,10 +68,10 @@ - - + + From 113b8ca29e5ed6738dff724248104df80e21d179 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Mon, 21 Jul 2025 20:30:53 -0300 Subject: [PATCH 06/16] [IMP] refurbished --- .../models/stock_valuation_layer_recompute.py | 169 +++++++++--------- 1 file changed, 80 insertions(+), 89 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 5303c71b8..5f7372c63 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -65,12 +65,33 @@ def delete_adjust_compute_lines(self): manual_slv = self.env['stock.valuation.layer'].search( [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id), ('create_uid', '=', 1), ('stock_move_id', '=', False)] , order="create_date desc") - manual_slv.mapped('account_move_id').button_draft() - manual_slv.mapped('account_move_id').unlink() - manual_slv.unlink() + manual_slv.sudo().mapped('account_move_id').button_draft() + manual_slv.sudo().mapped('account_move_id').unlink() + manual_slv.sudo().unlink() self.action_compute_lines() + def _prepare_new_values(self, from_currency_id, to_currency_id, qty, unit_cost, layer_date, manual_currency_rate=0): + is_company_currency = from_currency_id == self.company_id.currency_id + if manual_currency_rate and is_company_currency: + new_unit_cost_in_to_currency = unit_cost * manual_currency_rate + elif manual_currency_rate and not is_company_currency: + new_unit_cost_in_to_currency = unit_cost / manual_currency_rate + else: + new_unit_cost_in_to_currency = from_currency_id._convert( + from_amount=unit_cost, + to_currency=to_currency_id, + company=self.company_id, + date=layer_date, + ) + + if is_company_currency: + return [unit_cost, unit_cost * qty,new_unit_cost_in_to_currency, new_unit_cost_in_to_currency * qty,'manual rate' if manual_currency_rate else 'slv'] + return [new_unit_cost_in_to_currency,new_unit_cost_in_to_currency * qty,unit_cost,unit_cost * qty,'manual rate' if manual_currency_rate else 'slv'] + + def _get_standard_price(self, new_value, standard_price, quantity_at_time, quantity): + return (new_value + standard_price * (quantity_at_time - quantity)) / quantity_at_time if quantity_at_time else standard_price + def action_compute_lines(self): last_manual_svl_id = self.env['stock.valuation.layer'].search( @@ -84,6 +105,7 @@ def action_compute_lines(self): quantity_at_time = 0 standard_price_in_currency = 0 standard_price = 0 + description = '' self.initial_amount_in_currency = self.product_id.with_company(self.company_id.id).standard_price_in_currency self.initial_amount = self.product_id.with_company(self.company_id.id).standard_price @@ -98,21 +120,19 @@ def action_compute_lines(self): } quantity_at_time = quantity_at_time + svl_id.quantity + # Si el movimento es de salida o de inventario, valor es el registrado en el producto if svl_id.stock_move_id and (svl_id.stock_move_id._is_out() or svl_id.stock_move_id.is_inventory): - # Si el movimento es de salida o de inventario, valor es el registrado en el producto standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency standard_price = standard_price if standard_price else svl_id.unit_cost new_unit_cost = standard_price new_value = standard_price * svl_id.quantity - new_unit_cost_in_currency = standard_price_in_currency new_value_in_currency = standard_price_in_currency * svl_id.quantity svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' - # es un ajuste? - #elif svl_id.description.startswith('Valor del producto modificado') or svl_id.description.startswith('Manual'): + # es un ajuste? si no tiene movimiento de stock elif not svl_id.stock_move_id: new_value_in_currency = svl_id.value_in_currency new_unit_cost_in_currency = svl_id.unit_cost_in_currency @@ -124,9 +144,10 @@ def action_compute_lines(self): svl_type = 'ajustement' + # Es una devolucion elif svl_id.stock_move_id and svl_id.stock_move_id._is_returned(valued_type='in'): - # Si es una devolucion y existe el movimiento de origen - # el valor de avco sale del mov de origen sino sale de producto + # Si existe el movimiento de origen + # el valor de avco sale del mov de origen if svl_id.stock_move_id.origin_returned_move_id: for temp_vals in lines: @@ -141,6 +162,7 @@ def action_compute_lines(self): svl_type = 'return of %s ' % temp_vals[2]['layer_id'] break + # sino sale de producto else: new_value_in_currency = standard_price_in_currency * svl_id.quantity new_unit_cost_in_currency = standard_price_in_currency @@ -149,91 +171,60 @@ def action_compute_lines(self): svl_type = 'ret_without_move' - elif svl_id.manual_currency_rate: - # caso viene de un landed cost con manual currency rate - if svl_id.stock_landed_cost_id.inverse_currency_rate: - - new_value = svl_id.value - new_unit_cost = svl_id.unit_cost - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - - new_value_in_currency = svl_id.value * svl_id.manual_currency_rate - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - - svl_type = 'landed manual rate %s' % svl_id.manual_currency_rate - # caso viene de una compra con manual currency rate - elif svl_id.stock_move_id.picking_id.currency_rate and svl_id.stock_move_id.purchase_line_id.order_id.currency_id == svl_id.stock_move_id.picking_id.valuation_currency_id: - price_unit = svl_id.stock_move_id.purchase_line_id.price_unit / svl_id.stock_move_id.picking_id.currency_rate - - new_value_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit * svl_id.quantity - new_unit_cost_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - - - new_value = price_unit * svl_id.quantity - new_unit_cost = price_unit - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - svl_type = 'purchase manual rate %s' % svl_id.manual_currency_rate - # Otros casos ? - else: - new_value = svl_id.value - new_unit_cost = svl_id.unit_cost - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - - new_value_in_currency = svl_id.value * svl_id.manual_currency_rate - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'manual currency rate %s' % svl_id.manual_currency_rate - else: - if svl_id.stock_landed_cost_id.valuation_currency_id: - new_value_in_currency = svl_id.currency_id._convert( - from_amount=svl_id.value, - to_currency=svl_id.valuation_currency_id, - company=svl_id.company_id, - date=svl_id.create_date, - ) - new_value = svl_id.value - new_unit_cost = svl_id.unit_cost - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'landed cost' - - elif svl_id.stock_move_id.picking_id.valuation_currency_id and svl_id.stock_move_id.purchase_line_id.order_id.currency_id == svl_id.stock_move_id.picking_id.valuation_currency_id: - - new_value = svl_id.valuation_currency_id._convert( - from_amount=svl_id.value_in_currency, - to_currency=svl_id.currency_id, - company=svl_id.company_id, - date=svl_id.create_date, + # landed cost + elif svl_id.stock_landed_cost_id: + new_value, new_unit_cost, new_value_in_currency, new_unit_cost_in_currency, description = self._prepare_new_values( + from_currency_id=self.company_id.currency_id, + to_currency_id=svl_id.stock_landed_cost_id.valuation_currency_id, + qty=svl_id.quantity, + unit_cost=svl_id.value, + layer_date=svl_id.create_date, + manual_currency_rate=svl_id.manual_currency_rate ) - new_value_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit * svl_id.quantity - new_unit_cost_in_currency = svl_id.stock_move_id.purchase_line_id.price_unit - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - - - new_value = new_value - new_unit_cost = new_value / svl_id.quantity if svl_id.quantity else 0 - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - svl_type = 'purchase' + standard_price = self._get_standard_price(new_value, standard_price, quantity_at_time, svl_id.quantity) + standard_price_in_currency = self._get_standard_price(new_value_in_currency, standard_price_in_currency, quantity_at_time, svl_id.quantity) + svl_type = 'landed cost %s' % description + # purchase + elif svl_id.stock_move_id and svl_id.stock_move_id.purchase_line_id: + # purchase in company currency + if svl_id.stock_move_id.purchase_line_id.order_id.currency_id == self.company_id.currency_id: + new_unit_cost, new_value, new_unit_cost_in_currency, new_value_in_currency, description = self._prepare_new_values( + from_currency_id=self.company_id.currency_id, + to_currency_id= self.valuation_currency_id, + qty=svl_id.quantity, + unit_cost=svl_id.stock_move_id.purchase_line_id.price_unit, + layer_date=svl_id.create_date, + manual_currency_rate=svl_id.manual_currency_rate + ) + standard_price = self._get_standard_price(new_value, standard_price, quantity_at_time, svl_id.quantity) + standard_price_in_currency = self._get_standard_price(new_value_in_currency, standard_price_in_currency, quantity_at_time, svl_id.quantity) + svl_type = 'Purchase %s' % description else: - new_value_in_currency = svl_id.currency_id._convert( - from_amount=svl_id.value, - to_currency=svl_id.valuation_currency_id, - company=svl_id.company_id, - date=svl_id.create_date, + new_unit_cost, new_value, new_unit_cost_in_currency, new_value_in_currency, description = self._prepare_new_values( + from_currency_id=self.valuation_currency_id, + to_currency_id=self.company_id.currency_id, + qty=svl_id.quantity, + unit_cost=svl_id.stock_move_id.purchase_line_id.price_unit, + layer_date=svl_id.create_date, + manual_currency_rate=svl_id.manual_currency_rate + ) + standard_price = self._get_standard_price(new_value, standard_price, quantity_at_time, svl_id.quantity) + standard_price_in_currency = self._get_standard_price(new_value_in_currency, standard_price_in_currency, quantity_at_time, svl_id.quantity) + svl_type = 'Purchase %s' % description + else: + new_unit_cost, new_value, new_unit_cost_in_currency, new_value_in_currency, description = self._prepare_new_values( + from_currency_id=self.company_id.currency_id, + to_currency_id=self.valuation_currency_id, + qty=svl_id.quantity, + unit_cost=svl_id.price_unit, + layer_date=svl_id.create_date, + manual_currency_rate=svl_id.manual_currency_rate ) - new_value = svl_id.value - new_unit_cost = svl_id.unit_cost - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price - - new_unit_cost_in_currency = new_value_in_currency / svl_id.quantity if svl_id.quantity else 0 - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - svl_type = 'slv' + standard_price = self._get_standard_price(new_value, standard_price, quantity_at_time, svl_id.quantity) + standard_price_in_currency = self._get_standard_price(new_value_in_currency, standard_price_in_currency, quantity_at_time, svl_id.quantity) + svl_type = 'slv %s' % description # Si no queda producto el precio es 0 if quantity_at_time == 0: From a3b33a00934f66a698370c9d57fc5f49f6d81213 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Mon, 28 Jul 2025 18:08:14 -0300 Subject: [PATCH 07/16] [FIX] fix purchase outs --- .../models/stock_valuation_layer_recompute.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 5f7372c63..80709faf9 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -121,7 +121,7 @@ def action_compute_lines(self): quantity_at_time = quantity_at_time + svl_id.quantity # Si el movimento es de salida o de inventario, valor es el registrado en el producto - if svl_id.stock_move_id and (svl_id.stock_move_id._is_out() or svl_id.stock_move_id.is_inventory): + if svl_id.stock_move_id and ((svl_id.stock_move_id._is_out() and not svl_id.stock_move_id.purchase_line_id ) or svl_id.stock_move_id.is_inventory): standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency standard_price = standard_price if standard_price else svl_id.unit_cost @@ -186,6 +186,21 @@ def action_compute_lines(self): standard_price = self._get_standard_price(new_value, standard_price, quantity_at_time, svl_id.quantity) standard_price_in_currency = self._get_standard_price(new_value_in_currency, standard_price_in_currency, quantity_at_time, svl_id.quantity) svl_type = 'landed cost %s' % description + # purchase refund + elif svl_id.stock_move_id and svl_id.stock_move_id.purchase_line_id and svl_id.stock_move_id.origin_returned_move_id: + for temp_vals in lines: + if temp_vals[2] and temp_vals[2]['layer_id'] in svl_id.stock_move_id.origin_returned_move_id.stock_valuation_layer_ids.ids: + new_value_in_currency = temp_vals[2]['new_unit_cost_in_currency'] * svl_id.quantity + new_unit_cost_in_currency = temp_vals[2]['new_unit_cost_in_currency'] + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + new_value = temp_vals[2]['new_unit_cost'] * svl_id.quantity + new_unit_cost = temp_vals[2]['new_unit_cost'] + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + + svl_type = 'purchase refund of %s ' % temp_vals[2]['layer_id'] + + break + # purchase elif svl_id.stock_move_id and svl_id.stock_move_id.purchase_line_id: # purchase in company currency @@ -218,7 +233,7 @@ def action_compute_lines(self): from_currency_id=self.company_id.currency_id, to_currency_id=self.valuation_currency_id, qty=svl_id.quantity, - unit_cost=svl_id.price_unit, + unit_cost=svl_id.unit_cost, layer_date=svl_id.create_date, manual_currency_rate=svl_id.manual_currency_rate ) @@ -274,8 +289,8 @@ def action_manual_slv_revaluation(self): line_id.layer_id.write({ 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, 'value_in_currency':line_id.new_value_in_currency, - 'unit_cost': line_id.new_unit_cost_in_currency, - 'value':line_id.new_value_in_currency + 'unit_cost': line_id.new_unit_cost, + 'value':line_id.new_value }) lines = [] product_move_line_ids = line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id) From 8f17f32d6eba0f1de1a2b3b8c8eccbfaf178c78d Mon Sep 17 00:00:00 2001 From: Felipe Garcia Suez Date: Wed, 30 Jul 2025 13:00:26 -0300 Subject: [PATCH 08/16] [IMP] stock_currency_valuation: Added final_rate and search view --- .../models/stock_valuation_layer_recompute.py | 12 ++++++++++ .../views/stock_valuation_layer_recompute.xml | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 80709faf9..c7e6e157b 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -33,6 +33,10 @@ class StockValuationLayerRecompute(models.Model): last_manual_svl_id = fields.Many2one('stock.valuation.layer') amount_changed = fields.Boolean() slv_changed = fields.Boolean() + final_rate = fields.Float( + string='Final Rate', + compute="_compute_final_rate", + ) state = fields.Selection([ ('draft', 'Draft'), @@ -42,6 +46,14 @@ class StockValuationLayerRecompute(models.Model): ('cancel', 'Cancelled') ], default='draft', string='Status', required=True, readonly=True, copy=False) + @api.depends('final_amount', 'final_amount_in_currency') + def _compute_final_rate(self): + for rec in self: + if rec.final_amount_in_currency: + rec.final_rate = rec.final_amount / rec.final_amount_in_currency + else: + rec.final_rate = 0.0 + @api.onchange('product_id', 'company_id') def _onchange_product_id(self): self.line_ids = False diff --git a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml index a1b3d82d3..3673b6134 100644 --- a/stock_currency_valuation/views/stock_valuation_layer_recompute.xml +++ b/stock_currency_valuation/views/stock_valuation_layer_recompute.xml @@ -24,6 +24,8 @@ + + @@ -78,6 +80,28 @@ + + stock.valuation.layer.recompute.search + stock.valuation.layer.recompute + search + + + + + + + + + + + + + + + + + + Recompute layer ir.actions.act_window From a5efd25d63402fde57d338f2be3c213b030c5502 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Wed, 30 Jul 2025 20:18:54 -0300 Subject: [PATCH 09/16] [IMP] --- .../models/stock_valuation_layer_recompute.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index c7e6e157b..43935b6b3 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -36,6 +36,7 @@ class StockValuationLayerRecompute(models.Model): final_rate = fields.Float( string='Final Rate', compute="_compute_final_rate", + store=True, ) state = fields.Selection([ @@ -141,19 +142,32 @@ def action_compute_lines(self): new_value = standard_price * svl_id.quantity new_unit_cost_in_currency = standard_price_in_currency new_value_in_currency = standard_price_in_currency * svl_id.quantity - svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' # es un ajuste? si no tiene movimiento de stock elif not svl_id.stock_move_id: - new_value_in_currency = svl_id.value_in_currency - new_unit_cost_in_currency = svl_id.unit_cost_in_currency - standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency - new_value = svl_id.value new_unit_cost = svl_id.unit_cost - standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price + # before https://github.com/ingadhoc/stock/pull/675 + if svl_id.create_date < fields.Datetime.from_string('2025-03-31 16:00:00'): + new_unit_cost_in_currency = self.company_id.currency_id._convert( + from_amount=new_unit_cost, + to_currency=self.valuation_currency_id, + company=self.company_id, + date=svl_id.create_date, + ) + new_value_in_currency = self.company_id.currency_id._convert( + from_amount=new_value, + to_currency=self.valuation_currency_id, + company=self.company_id, + date=svl_id.create_date, + ) + else: + new_value_in_currency = svl_id.value_in_currency + new_unit_cost_in_currency = svl_id.unit_cost_in_currency + standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency + standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price svl_type = 'ajustement' # Es una devolucion From 2a6f72dd1b23c41a59d2090349e23ef2a5705724 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Fri, 1 Aug 2025 07:53:56 -0300 Subject: [PATCH 10/16] [FIX] Comment unused lines --- .../models/stock_valuation_layer_recompute.py | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 43935b6b3..440fd7a7e 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -148,24 +148,23 @@ def action_compute_lines(self): elif not svl_id.stock_move_id: new_value = svl_id.value new_unit_cost = svl_id.unit_cost - # before https://github.com/ingadhoc/stock/pull/675 - if svl_id.create_date < fields.Datetime.from_string('2025-03-31 16:00:00'): - new_unit_cost_in_currency = self.company_id.currency_id._convert( - from_amount=new_unit_cost, - to_currency=self.valuation_currency_id, - company=self.company_id, - date=svl_id.create_date, - ) - new_value_in_currency = self.company_id.currency_id._convert( - from_amount=new_value, - to_currency=self.valuation_currency_id, - company=self.company_id, - date=svl_id.create_date, - ) - else: - new_value_in_currency = svl_id.value_in_currency - new_unit_cost_in_currency = svl_id.unit_cost_in_currency - + # # before https://github.com/ingadhoc/stock/pull/675 + # if svl_id.create_date < fields.Datetime.from_string('2025-03-31 16:00:00'): + # new_unit_cost_in_currency = self.company_id.currency_id._convert( + # from_amount=new_unit_cost, + # to_currency=self.valuation_currency_id, + # company=self.company_id, + # date=svl_id.create_date, + # ) + # new_value_in_currency = self.company_id.currency_id._convert( + # from_amount=new_value, + # to_currency=self.valuation_currency_id, + # company=self.company_id, + # date=svl_id.create_date, + # ) + # else: + new_value_in_currency = svl_id.value_in_currency + new_unit_cost_in_currency = svl_id.unit_cost_in_currency standard_price_in_currency = (new_value_in_currency + standard_price_in_currency * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price_in_currency standard_price = (new_value + standard_price * (quantity_at_time - svl_id.quantity)) / quantity_at_time if quantity_at_time else standard_price svl_type = 'ajustement' @@ -268,9 +267,9 @@ def action_compute_lines(self): svl_type = 'slv %s' % description # Si no queda producto el precio es 0 - if quantity_at_time == 0: - standard_price_in_currency = 0 - standard_price = 0 + # if quantity_at_time == 0: + # standard_price_in_currency = 0 + # standard_price = 0 vals['new_value'] = new_value vals['new_unit_cost'] = new_unit_cost From 347bf319aa5f682fc487bbe5967ff15e22c827aa Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Thu, 14 Aug 2025 12:25:18 -0300 Subject: [PATCH 11/16] [fix] fis stock value --- .../models/stock_valuation_layer_recompute.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 440fd7a7e..801ca286e 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -133,8 +133,18 @@ def action_compute_lines(self): } quantity_at_time = quantity_at_time + svl_id.quantity + if svl_id.stock_move_id and svl_id.stock_move_id.is_inventory: + standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency + standard_price = standard_price if standard_price else svl_id.unit_cost + + new_unit_cost = svl_id.unit_cost + new_value = svl_id.value + new_unit_cost_in_currency = svl_id.unit_cost_in_currency + new_value_in_currency = svl_id.value_in_currency + svl_type = 'inventory' + # Si el movimento es de salida o de inventario, valor es el registrado en el producto - if svl_id.stock_move_id and ((svl_id.stock_move_id._is_out() and not svl_id.stock_move_id.purchase_line_id ) or svl_id.stock_move_id.is_inventory): + elif svl_id.stock_move_id and (svl_id.stock_move_id._is_out() and not svl_id.stock_move_id.purchase_line_id ): standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency standard_price = standard_price if standard_price else svl_id.unit_cost @@ -142,7 +152,7 @@ def action_compute_lines(self): new_value = standard_price * svl_id.quantity new_unit_cost_in_currency = standard_price_in_currency new_value_in_currency = standard_price_in_currency * svl_id.quantity - svl_type = 'inventory' if svl_id.stock_move_id.is_inventory else 'out' + svl_type = 'out' # es un ajuste? si no tiene movimiento de stock elif not svl_id.stock_move_id: From 8d657c82c32fbb0b8a148ee8a1d48be35dba38ce Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Thu, 21 Aug 2025 15:19:41 -0300 Subject: [PATCH 12/16] [IMP] Mofifico el caso de salidas a cero --- .../models/stock_valuation_layer_recompute.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 801ca286e..75fc4f29f 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -144,9 +144,13 @@ def action_compute_lines(self): svl_type = 'inventory' # Si el movimento es de salida o de inventario, valor es el registrado en el producto - elif svl_id.stock_move_id and (svl_id.stock_move_id._is_out() and not svl_id.stock_move_id.purchase_line_id ): - standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency - standard_price = standard_price if standard_price else svl_id.unit_cost + elif svl_id.stock_move_id and (svl_id.stock_move_id._is_out() ): + if len(lines) == 0: + standard_price_in_currency = svl_id.unit_cost_in_currency + standard_price = svl_id.unit_cost + else: + standard_price_in_currency = standard_price_in_currency + standard_price = standard_price new_unit_cost = standard_price new_value = standard_price * svl_id.quantity From 9e315bc140f793e63f35f6b6683cadec47efa008 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Tue, 9 Sep 2025 14:35:35 -0300 Subject: [PATCH 13/16] [FIX] divide write --- .../models/stock_valuation_layer_recompute.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 75fc4f29f..329a42840 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -150,7 +150,7 @@ def action_compute_lines(self): standard_price = svl_id.unit_cost else: standard_price_in_currency = standard_price_in_currency - standard_price = standard_price + standard_price = standard_price new_unit_cost = standard_price new_value = standard_price * svl_id.quantity @@ -326,11 +326,13 @@ def action_manual_slv_revaluation(self): if line_id.layer_id.stock_landed_cost_id: raise UserError('No puedo ajustar un landed cost') line_id.layer_id.write({ - 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, - 'value_in_currency':line_id.new_value_in_currency, 'unit_cost': line_id.new_unit_cost, 'value':line_id.new_value }) + line_id.layer_id.write({ + 'unit_cost_in_currency': line_id.new_unit_cost_in_currency, + 'value_in_currency':line_id.new_value_in_currency, + }) lines = [] product_move_line_ids = line_id.layer_id.account_move_id.line_ids.filtered(lambda x: x.product_id == self.product_id) #agrego las full reconiliaciones From 8c3df7a470dd26c5777fd3b8f8fd077117f74683 Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Wed, 10 Sep 2025 11:49:47 -0300 Subject: [PATCH 14/16] [IMP] stock_currency_valuation: cambio la manera en que computa los invetarios actualizando los datos --- .../models/stock_valuation_layer_recompute.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index 329a42840..f6c261b43 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -137,10 +137,10 @@ def action_compute_lines(self): standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency standard_price = standard_price if standard_price else svl_id.unit_cost - new_unit_cost = svl_id.unit_cost - new_value = svl_id.value - new_unit_cost_in_currency = svl_id.unit_cost_in_currency - new_value_in_currency = svl_id.value_in_currency + new_unit_cost = standard_price + new_value = standard_price * svl_id.quantity + new_unit_cost_in_currency = standard_price_in_currency + new_value_in_currency = standard_price_in_currency * svl_id.quantity svl_type = 'inventory' # Si el movimento es de salida o de inventario, valor es el registrado en el producto From b6d786c45cc482164a475594d8e4a388a328a27c Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Tue, 2 Dec 2025 16:07:10 -0300 Subject: [PATCH 15/16] [IMP] Fix credit in currency --- stock_currency_valuation/__manifest__.py | 2 +- .../models/stock_valuation_layer_recompute.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/stock_currency_valuation/__manifest__.py b/stock_currency_valuation/__manifest__.py index 20fc19459..51a42d8f1 100644 --- a/stock_currency_valuation/__manifest__.py +++ b/stock_currency_valuation/__manifest__.py @@ -1,6 +1,6 @@ { 'name': 'Stock currency valuation', - 'version': "16.0.2.2.0", + 'version': "16.0.3.0.0", 'category': 'Warehouse Management', 'sequence': 14, 'summary': '', diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index f6c261b43..d411fdcba 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -1,6 +1,7 @@ -from odoo import Command, api, fields, models from odoo.exceptions import UserError +from odoo import Command, api, fields, models + def patch_check_reconciliation(self): return @@ -340,11 +341,14 @@ def action_manual_slv_revaluation(self): move_ids = product_move_line_ids.mapped('move_id') move_ids.button_draft() for move_line in product_move_line_ids: - multiplier = 1 if move_line.amount_currency >= 0 else -1 + multiplier = 1 if move_line.credit == 0 else -1 field = 'debit' if move_line.credit == 0 else 'credit' + # OJO el valor de currency puede ser positivo o negativo + # pero enel asiento siempre es positivo para debit y negativo para credit + # por eso multiplico el valor absoluto por el signo lines.append(Command.update(move_line.id,{ - 'amount_currency': line_id.new_value_in_currency * multiplier, - field: line_id.new_value, + 'amount_currency': abs(line_id.new_value_in_currency) * multiplier, + field: abs(line_id.new_value), })) if lines: line_id.layer_id.account_move_id.line_ids = lines From 8759b9ef4e35159e9e90f0841717c537a7596c5e Mon Sep 17 00:00:00 2001 From: Martin Quinteros Date: Fri, 26 Dec 2025 13:11:07 -0300 Subject: [PATCH 16/16] [IMP] set to zero svl --- .../models/stock_valuation_layer_recompute.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/stock_currency_valuation/models/stock_valuation_layer_recompute.py b/stock_currency_valuation/models/stock_valuation_layer_recompute.py index d411fdcba..977bedbe3 100644 --- a/stock_currency_valuation/models/stock_valuation_layer_recompute.py +++ b/stock_currency_valuation/models/stock_valuation_layer_recompute.py @@ -113,6 +113,8 @@ def action_compute_lines(self): , order="create_date desc", limit=1) self.last_manual_svl_id = last_manual_svl_id + lines_to_zero = self.env.context.get('lines_to_zero', {}) + leaf = [('company_id', '=', self.company_id.id), ('product_id', '=', self.product_id.id)] svl_ids = self.env['stock.valuation.layer'].search(leaf, order="create_date asc") lines = [Command.clear()] @@ -133,8 +135,15 @@ def action_compute_lines(self): 'layer_value_in_currency': svl_id.value_in_currency, } quantity_at_time = quantity_at_time + svl_id.quantity - - if svl_id.stock_move_id and svl_id.stock_move_id.is_inventory: + if svl_id.id in lines_to_zero: + new_unit_cost = 0 + new_value = 0 + new_unit_cost_in_currency = 0 + new_value_in_currency = 0 + quantity_at_time = quantity_at_time - svl_id.quantity + svl_type = 'zero' + + elif svl_id.stock_move_id and svl_id.stock_move_id.is_inventory: standard_price_in_currency = standard_price_in_currency if standard_price_in_currency else svl_id.unit_cost_in_currency standard_price = standard_price if standard_price else svl_id.unit_cost @@ -302,7 +311,8 @@ def action_compute_lines(self): need_change_4 = self.currency_id.compare_amounts(svl_id.unit_cost, new_unit_cost) != 0.0 need_change_5 = svl_id.id > last_manual_svl_id.id or not last_manual_svl_id - vals['need_changes'] = True if (need_change_1 or need_change_2 or need_change_3 or need_change_4) and need_change_5 else False + need_change_6 = svl_id.id in lines_to_zero + vals['need_changes'] = True if (need_change_1 or need_change_2 or need_change_3 or need_change_4 or need_change_6) and need_change_5 else False lines.append(Command.create(vals),) self.line_ids = lines self.final_amount_in_currency = standard_price_in_currency