odoo18/custom_addons/costing_mrp_bom/models/mrp.py

114 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from ast import literal_eval
from collections import defaultdict
from odoo import fields, models, _, api
from odoo.tools import float_round
from odoo.exceptions import ValidationError
class MrpProduction(models.Model):
_inherit = 'mrp.production'
def _get_moves_raw_values(self):
moves = []
for production in self:
if not production.bom_id:
continue
factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id) / production.bom_id.product_qty
_boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id, never_attribute_values=production.never_product_template_attribute_value_ids)
for bom_line, line_data in lines:
# if bom_line.child_bom_id and bom_line.child_bom_id.type == 'phantom' or\
# bom_line.product_id.type != 'consu':
if bom_line.child_bom_id and bom_line.child_bom_id.type == 'phantom':
continue
operation = bom_line.operation_id.id or line_data['parent_line'] and line_data['parent_line'].operation_id.id
moves.append(production._get_move_raw_values(
bom_line.product_id,
line_data['qty'],
bom_line.product_uom_id,
operation,
bom_line
))
return moves
def action_confirm(self):
res = super(MrpProduction,self).action_confirm()
for rec in self:
rec.product_id.button_bom_cost()
return res
class MrpBomLine(models.Model):
_inherit = 'mrp.bom.line'
unit_cost = fields.Float(compute='_compute_product_price', digits=(16, 2), string="Unit Cost")
total_price = fields.Float(compute='_compute_total_price', string="Total Cost")
is_service_product = fields.Float(compute='_compute_is_service_product', default=False)
@api.depends('product_id')
def _compute_product_price(self):
for rec in self:
if rec.product_id:
# Get product cost in the company context
standard_price = rec.product_id.with_company(rec.env.company).standard_price
# Convert cost from product's UoM to BoM line UoM
unit_cost = rec.product_id.uom_id._compute_price(
standard_price, rec.product_uom_id
)
rec.unit_cost = unit_cost
else:
rec.unit_cost = 0.0
@api.depends('unit_cost', 'product_qty')
def _compute_total_price(self):
for rec in self:
if rec.product_id:
# Get product cost in the company context
standard_price = rec.product_id.with_company(rec.env.company).standard_price
# Convert cost from product's UoM to BoM line UoM
unit_cost = rec.product_id.uom_id._compute_price(
standard_price, rec.product_uom_id
)
else:
unit_cost = 0.0
rec.total_price = unit_cost * rec.product_qty
@api.depends('product_id')
def _compute_is_service_product(self):
for rec in self:
rec.is_service_product = True if rec.product_id.type == 'service' else False
@api.constrains('product_id', 'bom_id')
@api.onchange('product_id', 'bom_id')
def _check_unique_product_in_bom(self):
for line in self:
# Find all lines in the same BoM with the same product
duplicate_lines = line.bom_id.bom_line_ids.filtered(
lambda l: l.product_id == line.product_id
)
if len(duplicate_lines) > 1:
raise ValidationError(
f"The product '{line.product_id.display_name}' is already used in this BoM."
)
class StockMove(models.Model):
_inherit = 'stock.move'
is_service_product = fields.Float(compute='_compute_is_service_product', default=False)
@api.depends('product_id')
def _compute_is_service_product(self):
for rec in self:
rec.is_service_product = True if rec.product_id.type == 'service' else False