90 lines
4.4 KiB
Python
90 lines
4.4 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||
|
|
||
|
import itertools
|
||
|
from odoo import api, fields, models, _
|
||
|
from odoo.tools.float_utils import float_is_zero
|
||
|
from odoo.tools.misc import groupby
|
||
|
|
||
|
|
||
|
class StockQuant(models.Model):
|
||
|
_inherit = 'stock.quant'
|
||
|
|
||
|
value = fields.Monetary('Value', compute='_compute_value', groups='stock.group_stock_manager')
|
||
|
currency_id = fields.Many2one('res.currency', compute='_compute_value', groups='stock.group_stock_manager')
|
||
|
accounting_date = fields.Date(
|
||
|
'Accounting Date',
|
||
|
help="Date at which the accounting entries will be created"
|
||
|
" in case of automated inventory valuation."
|
||
|
" If empty, the inventory date will be used.")
|
||
|
cost_method = fields.Selection(related="product_categ_id.property_cost_method")
|
||
|
|
||
|
@api.model
|
||
|
def _should_exclude_for_valuation(self):
|
||
|
"""
|
||
|
Determines if a quant should be excluded from valuation based on its ownership.
|
||
|
:return: True if the quant should be excluded from valuation, False otherwise.
|
||
|
"""
|
||
|
self.ensure_one()
|
||
|
return self.owner_id and self.owner_id != self.company_id.partner_id
|
||
|
|
||
|
@api.depends('company_id', 'location_id', 'owner_id', 'product_id', 'quantity')
|
||
|
def _compute_value(self):
|
||
|
""" (Product.value_svl / Product.quantity_svl) * quant.quantity, i.e. average unit cost * on hand qty
|
||
|
"""
|
||
|
self.fetch(['company_id', 'location_id', 'owner_id', 'product_id', 'quantity', 'lot_id'])
|
||
|
self.value = 0
|
||
|
for quant in self:
|
||
|
quant.currency_id = quant.company_id.currency_id
|
||
|
if not quant.location_id or not quant.product_id or\
|
||
|
not quant.location_id._should_be_valued() or\
|
||
|
quant._should_exclude_for_valuation() or\
|
||
|
float_is_zero(quant.quantity, precision_rounding=quant.product_id.uom_id.rounding):
|
||
|
continue
|
||
|
if quant.product_id.lot_valuated:
|
||
|
quantity = quant.lot_id.with_company(quant.company_id).quantity_svl
|
||
|
value_svl = quant.lot_id.with_company(quant.company_id).value_svl
|
||
|
else:
|
||
|
quantity = quant.product_id.with_company(quant.company_id).quantity_svl
|
||
|
value_svl = quant.product_id.with_company(quant.company_id).value_svl
|
||
|
if float_is_zero(quantity, precision_rounding=quant.product_id.uom_id.rounding):
|
||
|
continue
|
||
|
quant.value = quant.quantity * value_svl / quantity
|
||
|
|
||
|
def _read_group_select(self, aggregate_spec, query):
|
||
|
# flag value as aggregatable, and manually sum the values from the
|
||
|
# records in the group
|
||
|
if aggregate_spec == 'value:sum':
|
||
|
return super()._read_group_select('id:recordset', query)
|
||
|
return super()._read_group_select(aggregate_spec, query)
|
||
|
|
||
|
def _read_group_postprocess_aggregate(self, aggregate_spec, raw_values):
|
||
|
if aggregate_spec == 'value:sum':
|
||
|
column = super()._read_group_postprocess_aggregate('id:recordset', raw_values)
|
||
|
return (sum(records.mapped('value')) for records in column)
|
||
|
return super()._read_group_postprocess_aggregate(aggregate_spec, raw_values)
|
||
|
|
||
|
def _apply_inventory(self):
|
||
|
for accounting_date, inventory_ids in groupby(self, key=lambda q: q.accounting_date):
|
||
|
inventories = self.env['stock.quant'].concat(*inventory_ids)
|
||
|
if accounting_date:
|
||
|
super(StockQuant, inventories.with_context(force_period_date=accounting_date))._apply_inventory()
|
||
|
inventories.accounting_date = False
|
||
|
else:
|
||
|
super(StockQuant, inventories)._apply_inventory()
|
||
|
|
||
|
def _get_inventory_move_values(self, qty, location_id, location_dest_id, package_id=False, package_dest_id=False):
|
||
|
res_move = super()._get_inventory_move_values(qty, location_id, location_dest_id, package_id, package_dest_id)
|
||
|
if not self.env.context.get('inventory_name'):
|
||
|
force_period_date = self.env.context.get('force_period_date', False)
|
||
|
if force_period_date:
|
||
|
res_move['name'] += _(' [Accounted on %s]', force_period_date)
|
||
|
return res_move
|
||
|
|
||
|
@api.model
|
||
|
def _get_inventory_fields_write(self):
|
||
|
""" Returns a list of fields user can edit when editing a quant in `inventory_mode`."""
|
||
|
res = super()._get_inventory_fields_write()
|
||
|
res += ['accounting_date']
|
||
|
return res
|