|
|
@ -19,7 +19,11 @@ |
|
|
|
# If not, see <http://www.gnu.org/licenses/>. |
|
|
|
# |
|
|
|
################################################################################ |
|
|
|
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': |
|
|
|