# -*- coding: utf-8 -*- from odoo import models, fields, api from odoo.exceptions import ValidationError import logging _logger = logging.getLogger(__name__) class MiscellaneousCost(models.Model): _name = 'miscellaneous_items' _description = 'Miscellaneous Items' name = fields.Char(string='Name') description = fields.Char(string='Description') cost = fields.Float(string='Cost') main_model_id = fields.Many2one('sos_fg_bom') class SOS_Fg_Bom(models.Model): _name = 'sos_fg_bom' _description = 'BOM of Finished Goods' name = fields.Char(string="Name", required=True) currency_id = fields.Many2one('res.currency', string='Currency') fg_bom_line_ids = fields.One2many('sos_fg_bom_line', 'bom_id', string='Material Lines',copy=True, ondelete="cascade") overall_total = fields.Monetary(compute='_compute_overall_total', string="Estimated Cost", currency_field='currency_id', readonly=True) sfg_cost = fields.Monetary(compute='_compute_sfg_cost', string="Total", currency_field='currency_id', readonly=True) component_cost = fields.Monetary(compute='_compute_component_cost', string="Total", currency_field='currency_id', readonly=True) miscellaneous_cost = fields.Monetary(compute='_compute_miscellaneous_cost', string="Total", currency_field='currency_id', readonly=True) sfg_bom_line_ids = fields.One2many('sos_sfg_bom_line', 'fg_bom_id', string='BOM Lines',copy=True, ondelete='cascade') fg_name = fields.Many2one('sos_fg', string='FG Name') miscellaneous_ids = fields.One2many('miscellaneous_items', 'main_model_id', string='Miscellaneous Costs',copy=True, ondelete='cascade') bom_version = fields.Char(string="BOM Version") is_primary = fields.Boolean(string="Set as Primary",help="This BOM will be used in Indent Plan",copy=False) responsible_person = fields.Many2many('res.users', string='Read Access allowed to') def write(self, vals): for record in self: if 'is_primary' in vals and vals['is_primary']: other_boms = self.env['sos_fg_bom'].search([ ('fg_name', '=', record.fg_name.id), ('id', '!=', record.id) ]) other_boms.write({'is_primary': False}) self._sync_unit_price_with_fg() result = super(SOS_Fg_Bom, self).write(vals) return result @api.returns('self', lambda value: value.id) def copy(self, default=None): if default is None: default = {} if 'bom_version' not in default: default['bom_version'] = f"{self.bom_version} (copy)" if 'name' not in default: default['name'] = f"{self.name} (copy)" if 'fg_name' not in default: default['fg_name'] = self.fg_name.id return super(SOS_Fg_Bom, self).copy(default) @api.constrains('name', 'fg_name', 'bom_version') def check_unique_values(self): for record in self: existing_records = self.search([ ('name', '=', record.name), ('fg_name', '=', record.fg_name.id), ('bom_version', '=', record.bom_version), ('id', '!=', record.id) ]) if existing_records: raise ValidationError("The combination of Name, FG Name, and BOM Version must be unique across all records.") @api.depends('sfg_cost','component_cost', 'miscellaneous_cost') def _compute_overall_total(self): for record in self: record.overall_total = record.sfg_cost + record.component_cost + record.miscellaneous_cost record._sync_unit_price_with_fg() @api.depends('sfg_bom_line_ids.unit_price') def _compute_component_cost(self): for record in self: record.component_cost = sum(line.total_cost for line in record.sfg_bom_line_ids) @api.depends('miscellaneous_ids.cost') def _compute_miscellaneous_cost(self): for record in self: record.miscellaneous_cost = sum(line.cost for line in record.miscellaneous_ids) @api.depends('fg_bom_line_ids.unit_price') def _compute_sfg_cost(self): for record in self: record.sfg_cost = sum(line.unit_price for line in record.fg_bom_line_ids) @api.model def create(self, vals): res = super(SOS_Fg_Bom, self).create(vals) res._sync_unit_price_with_fg() return res def _sync_unit_price_with_fg(self): sos_fg_obj = self.env['sos_fg'] for record in self: fg_record = sos_fg_obj.search([('id', '=', record.fg_name.id)], limit=1) if fg_record: try: fg_record.write({'unit_price': record.overall_total}) except Exception as e: print("Error updating unit price:", e) class SOS_Fg_Bom_Line(models.Model): _name = 'sos_fg_bom_line' _description = 'BOM of Finished Goods Lines' bom_id = fields.Many2one('sos_fg_bom', string="fg BOM Reference") primary_component_id = fields.Many2one('sos_material', string='Primary Part No') sfg_bom_id = fields.Many2one('sos_sfg_bom', string='SFG BOM Reference', domain="[('fg_name', '=', parent.fg_name)]", required=False) quantity = fields.Float(string="Qty", required=True,default=1) currency_id = fields.Many2one('res.currency') unit_price = fields.Monetary(compute='_compute_unit_price', string="Unit Price", currency_field='currency_id', readonly=True) total_cost = fields.Monetary(compute='_compute_total_cost', string="Estimated Cost", currency_field='currency_id', readonly=True) @api.onchange('bom_id') def _onchange_bom_id(self): if self.bom_id: return {'domain': {'sfg_bom_id': [('fg_name', '=', self.bom_id.fg_name.id)]}} else: return {'domain': {'sfg_bom_id': []}} @api.depends('primary_component_id.unit_price', 'sfg_bom_id.name', 'quantity') def _compute_unit_price(self): for record in self: if record.primary_component_id: record.unit_price = record.primary_component_id.unit_price elif record.sfg_bom_id: record.unit_price = record.sfg_bom_id.name.unit_price * record.quantity else: record.unit_price = 0 @api.depends('unit_price', 'quantity') def _compute_total_cost(self): for record in self: record.total_cost = record.unit_price * record.quantity