diff --git a/cancel_landed_cost_odoo/__manifest__.py b/cancel_landed_cost_odoo/__manifest__.py index 115bfa4bd..e17edfb44 100644 --- a/cancel_landed_cost_odoo/__manifest__.py +++ b/cancel_landed_cost_odoo/__manifest__.py @@ -21,7 +21,7 @@ ################################################################################ { 'name': "Cancel Landed Cost", - 'version': "17.0.1.0.0", + 'version': "17.0.1.0.1", 'category': 'Purchases,Accounting,Warehouse', 'summary': 'This module helps to cancel landed costs', 'description': 'This module helps to cancel Landed Costs and allows you ' diff --git a/cancel_landed_cost_odoo/models/stock_landed_cost.py b/cancel_landed_cost_odoo/models/stock_landed_cost.py index e1c6d32a7..cc889a930 100644 --- a/cancel_landed_cost_odoo/models/stock_landed_cost.py +++ b/cancel_landed_cost_odoo/models/stock_landed_cost.py @@ -19,7 +19,11 @@ # If not, see . # ################################################################################ -from odoo import fields, models +from odoo import fields, models, _ +from odoo.tools.float_utils import float_is_zero +from collections import defaultdict +from odoo.exceptions import UserError + class StockLandedCost(models.Model): @@ -52,6 +56,38 @@ class StockLandedCost(models.Model): 'once, it will hide the button and make' 'it invisible.') + def calculate_avco_price(self): + + for cost in self: + cost = cost.with_company(cost.company_id) + cost_to_add_byproduct = defaultdict(lambda: 0.0) + for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id): + remaining_qty = sum(line.move_id.stock_valuation_layer_ids.mapped('remaining_qty')) + + # Prorate the value at what's still in stock + move_qty = line.move_id.product_uom._compute_quantity(line.move_id.quantity, + line.move_id.product_id.uom_id) + cost_to_add = (remaining_qty / move_qty) * line.additional_landed_cost + + # Update the AVCO/FIFO + product = line.move_id.product_id + if product.cost_method in ['average', 'fifo']: + cost_to_add_byproduct[product] -= cost_to_add + # Products with manual inventory valuation are ignored because they do not need to create journal entries. + if product.valuation != "real_time": + continue + # `remaining_qty` is negative if the move is out and delivered proudcts that were not + # in stock. + qty_out = 0 + + # batch standard price computation avoid recompute quantity_svl at each iteration + products = self.env['product.product'].browse(p.id for p in cost_to_add_byproduct.keys()).with_company( + cost.company_id) + for product in products: # iterate on recordset to prefetch efficiently quantity_svl + if not float_is_zero(product.quantity_svl, precision_rounding=product.uom_id.rounding): + product.sudo().with_context(disable_auto_svl=True).standard_price += cost_to_add_byproduct[ + product] / product.quantity_svl + def action_landed_cost_cancel(self): """Cancels the landed cost record by deleting its associated accounting entries, stock valuation, and changes state to 'cancelled'. @@ -64,18 +100,8 @@ class StockLandedCost(models.Model): lambda line: line.move_id): product = line.move_id.product_id if product.cost_method == 'average': - original_price = product.standard_price - new_price = product.standard_price - line.additional_landed_cost - product.write({'standard_price': new_price}) - stock_valuation_layer = self.env['stock.valuation.layer'] \ - .search([('product_id', '=', product.id), - ('description', '=', f'Product value manually ' - f'modified (from {original_price} to {new_price})')], - limit=1) - if stock_valuation_layer: - stock_valuation_layer.account_move_id.button_draft() - stock_valuation_layer.account_move_id.sudo().unlink() - stock_valuation_layer.sudo().unlink() + self.calculate_avco_price() + if rec.account_move_id: account_id = rec.account_move_id account_move_ids = account_id.line_ids @@ -102,18 +128,8 @@ class StockLandedCost(models.Model): lambda line: line.move_id): product = line.move_id.product_id if product.cost_method == 'average': - original_price = product.standard_price - new_price = product.standard_price - line.additional_landed_cost - product.write({'standard_price': new_price}) - stock_valuation_layer = self.env['stock.valuation.layer'] \ - .search([('product_id', '=', product.id), - ('description', '=', f'Product value manually ' - f'modified (from {original_price} to {new_price})')], - limit=1) - if stock_valuation_layer: - stock_valuation_layer.account_move_id.button_draft() - stock_valuation_layer.account_move_id.sudo().unlink() - stock_valuation_layer.sudo().unlink() + self.calculate_avco_price() + if rec.account_move_id: account_id = rec.account_move_id account_move_ids = account_id.line_ids @@ -140,18 +156,7 @@ class StockLandedCost(models.Model): lambda line: line.move_id): product = line.move_id.product_id if product.cost_method == 'average': - original_price = product.standard_price - new_price = product.standard_price - line.additional_landed_cost - product.write({'standard_price': new_price}) - stock_valuation_layer = self.env['stock.valuation.layer'] \ - .search([('product_id', '=', product.id), - ('description', '=', f'Product value manually ' - f'modified (from {original_price} to {new_price})')], - limit=1) - if stock_valuation_layer: - stock_valuation_layer.account_move_id.button_draft() - stock_valuation_layer.account_move_id.sudo().unlink() - stock_valuation_layer.sudo().unlink() + self.calculate_avco_price() if rec.account_move_id: account_id = rec.account_move_id account_move_ids = account_id.line_ids @@ -167,6 +172,7 @@ class StockLandedCost(models.Model): rec.write({'state': 'cancel'}) rec.unlink() + def action_landed_cost_cancel_form(self): """Cancels the landed cost record and deletes its associated accounting entries and stock valuation. It also creates two entries @@ -188,18 +194,8 @@ class StockLandedCost(models.Model): lambda line: line.move_id): product = line.move_id.product_id if product.cost_method == 'average': - original_price = product.standard_price - new_price = product.standard_price - line.additional_landed_cost - product.write({'standard_price': new_price}) - stock_valuation_layer = self.env['stock.valuation.layer'] \ - .search([('product_id', '=', product.id), - ('description', '=', f'Product value manually ' - f'modified (from {original_price} to {new_price})')], - limit=1) - if stock_valuation_layer: - stock_valuation_layer.account_move_id.button_draft() - stock_valuation_layer.account_move_id.sudo().unlink() - stock_valuation_layer.sudo().unlink() + self.calculate_avco_price() + if self.account_move_id: account_id = self.account_move_id account_move_ids = account_id.line_ids @@ -212,6 +208,7 @@ class StockLandedCost(models.Model): self.valuation_adjustment_lines.unlink() if self.stock_valuation_layer_ids: self.sudo().stock_valuation_layer_ids.unlink() + landed_mode = self.env['ir.config_parameter'].sudo().get_param( 'cancel_landed_cost_odoo.land_cost_cancel_modes') if landed_mode == 'cancel':