Odoo Mindscape. Understand Odoo faster. Explore modules, fields, dependencies and version differences in one place instead of digging through the source code.

Module: WMS Accounting

Entity: product.product

Compute Method: _compute_value

Inputs Method Outputs
  • id
  • qty_available
  • standard_price
  • lot_valuated
  • uom_id
  • cost_method
  • total_value
company_id = self.env.company
self.company_currency_id = company_id.currency_id
products = self._with_valuation_context()
at_date = self.env.context.get('to_date')
original_value = at_date
at_date = fields.Datetime.to_datetime(at_date)
if (isinstance(original_value, date) and not isinstance(original_value, datetime)) or \
            (isinstance(original_value, str) and len(original_value) == 10):
            at_date = datetime.combine(at_date.date(), time.max)
if at_date:
            products = products.with_context(at_date=at_date, to_date=at_date)
std_price_by_company_id = {}
total_value_by_company_id = {}
lot_valuated_products_ids = {p.id for p in self if p.lot_valuated}
valued_quantity_by_product_id = defaultdict(float)
for company in self.env.companies:
            std_price_by_product_id = defaultdict(float)
            total_value_by_product_id = defaultdict(float)

            products = self.with_company(company.id).with_context(allowed_company_ids=company.ids)
            products = products._with_valuation_context()
            if at_date:
                products = products.with_context(at_date=at_date, to_date=at_date)

            env = products.env

            if lot_valuated_products_ids:
                domain = Domain([('product_id', 'in', lot_valuated_products_ids)])
                if not at_date and not self.env.context.get('warehouse_id'):
                    domain &= Domain([('product_qty', '!=', 0)])
                lots_by_product = env['stock.lot']._read_group(
                    domain,
                    groupby=['product_id'],
                    aggregates=['id:recordset']
                )
                # Collect all lots and trigger batch computation of total_value
                env['stock.lot'].browse(
                        lot.id
                        for _, lots in lots_by_product
                        for lot in lots
                ).mapped('total_value')
                for product, lots in lots_by_product:
                    value = sum(lots.mapped('total_value'))
                    std_price_by_product_id[product.id] = value / product.qty_available if product.qty_available else product.standard_price
                    total_value_by_product_id[product.id] = value

            product_ids_grouped_by_cost_method = defaultdict(set)
            ratio_by_product_id = {}
            for product in products:
                if product.lot_valuated:
                    continue
                product_whole_company_context = product
                if 'warehouse_id' in self.env.context:
                    product_whole_company_context = product.with_context(warehouse_id=False)
                if product.uom_id.is_zero(product.qty_available):
                    total_value_by_product_id[product.id] = 0
                    std_price_by_product_id[product.id] = product.standard_price
                    continue
                if product.uom_id.is_zero(product_whole_company_context.qty_available):
                    total_value_by_product_id[product.id] = product.standard_price * product.qty_available
                    std_price_by_product_id[product.id] = product.standard_price
                    continue
                if product.uom_id.compare(product.qty_available, product_whole_company_context.qty_available) != 0:
                    ratio = product.qty_available / product_whole_company_context.qty_available
                    ratio_by_product_id[product.id] = ratio

                product_ids_grouped_by_cost_method[product.cost_method].add(product.id)

            for cost_method, product_ids in product_ids_grouped_by_cost_method.items():
                products_to_value = products.env['product.product'].browse(product_ids).with_context(warehouse_id=False)
                # To remove once price_unit isn't truncate in sql anymore (no need of force_recompute)
                if cost_method == 'standard':
                    std_prices, total_values = products_to_value._run_standard_batch(at_date=at_date)
                elif cost_method == 'average':
                    std_prices, total_values = products_to_value._run_average_batch(at_date=at_date)
                else:
                    std_prices, total_values = products_to_value._run_fifo_batch(at_date=at_date)

                std_price_by_product_id.update(std_prices)
                total_value_by_product_id.update(total_values)

            for product in products:
                total_value = total_value_by_product_id.get(product.id, 0)
                total_value_by_product_id[product.id] = total_value * ratio_by_product_id.get(product.id, 1)
                valued_quantity_by_product_id[product.id] += product.qty_available

            std_price_by_company_id[company.id] = std_price_by_product_id
            total_value_by_company_id[company.id] = total_value_by_product_id
for product in self:
            product.total_value = sum(c.currency_id._convert(total_value_by_company_id[c.id].get(product.id, 0), self.env.company.currency_id) for c in self.env.companies)
            valued_quantity = valued_quantity_by_product_id[product.id]
            product.avg_cost = product.total_value / valued_quantity if valued_quantity else std_price_by_company_id[self.env.company.id].get(product.id, product.standard_price)

Back to entity