from odoo import models, fields, api import math from collections import defaultdict from odoo.tools.misc import format_amount class Battery_Installation_Requirement(models.Model): _name = 'sos_proposal_boq' _description = 'Battery Installation Details' _rec_name="proposal_id" _order = 'proposal_id asc' _sql_constraints = [ ('unique_proposal_id', 'unique(proposal_id)', 'Proposal ID must be unique!') ] proposal_id = fields.Many2one('sos_proposal_customer_requirement',string="Proposal ID", required= True, domain=lambda self: [('id', 'not in', self.env['sos_proposal_boq'].search([]).mapped('proposal_id').ids)]) customer_name = fields.Char(string="Customer Name") location = fields.Char(string="Location") number_of_batteries = fields.Integer(string="Number of Batteries") number_of_strings = fields.Integer(string="Number of Strings") number_of_ups = fields.Integer(string="Number of UPS",store=True) ups_rating_kva = fields.Integer(string="UPS Rating (KVA)") no_of_electrical_panel = fields.Integer(string="No of Electrical Panel") battery_capacity_ah = fields.Integer(string="Battery Capacity (AH)") products = fields.Selection([ ('BHMS 1.2V', 'BHMS 1.2V'), ('BHMS 2V', 'BHMS 2V'), ('BHMS 12V', 'BHMS 12V'), ('BHMS 48V', 'BHMS 48V'), ('BMS-HV', 'BMS-HV'), ('BMS-LV 100A', 'BMS-LV 100A'), ('BMS-LV 40A', 'BMS-LV 40A'), ('SBMS 55A', 'SBMS 55A'), ('MC 250W', 'MC 250W'), ('HeartTarang', 'HeartTarang') ], string="Products") main_master_count= fields.Integer(string="No of Master") main_slave_count= fields.Integer(string="No of Slave") line_ids_material = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Materials",copy=True) line_ids_sfg = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="Semi-Finished Goods",copy=True) line_ids_fg = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="Finished Goods",copy=True) line_ids_miscellaneous = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id',string="") line_ids_installation_kit = fields.One2many('sos_proposal_line_material_installation', 'ref_id',string="") boq_submitted_by_name = fields.Many2one('res.users', string='BOQ Submitted By') boq_submitted_by_image = fields.Image(related="boq_submitted_by_name.signature_image",readonly=True) boq_submitted_by_approved_on = fields.Datetime(string="Submitted On") currency_id = fields.Many2one( 'res.currency', string='Currency', default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False ) total_fg_cost = fields.Monetary(compute='_compute_total_fg_cost', string="Total FG Cost", currency_field='currency_id', readonly=True) total_sfg_cost = fields.Monetary(compute='_compute_total_sfg_cost', string="Total SFG Cost", currency_field='currency_id', readonly=True) total_material_cost = fields.Monetary(compute='_compute_total_material_cost', string="Total Material Cost", currency_field='currency_id', readonly=True) total_installation_material_cost = fields.Monetary(compute='_compute_total_installation_material_cost', string="Total Installation Cost", currency_field='currency_id', readonly=True) total_miscellaneous_cost = fields.Monetary(compute='_compute_total_miscellaneous_cost', string="Total Miscellaneous Cost", currency_field='currency_id', readonly=True) total_cost = fields.Monetary(compute='_compute_total_cost', string="Total Cost", currency_field='currency_id', readonly=True) acc_approved_by_name = fields.Many2one('res.users', string='Accounts By') acc_approved_by_image = fields.Image(related="acc_approved_by_name.signature_image",readonly=True) acc_approved_on = fields.Datetime(string="Approved On") warranty_cost = fields.Monetary(string="Warranty Cost", compute='_compute_warranty', store=True, currency_field='currency_id') margin = fields.Monetary(string="Opreational Cost",compute='_compute_margin', currency_field='currency_id') margin_per_battery = fields.Monetary(string="Opreational Cost per Battery", currency_field='currency_id') warranty_percentage = fields.Float(string="Warranty(%)") final_cost = fields.Monetary(string="Final Cost", compute='_compute_final_cost', store=True, currency_field='currency_id') final_cost_per_battery = fields.Monetary(string="Final Cost", compute='_compute_final_cost_per_battery', store=True, currency_field='currency_id') communication_type = fields.Selection([ ('wired', 'Wired'), ('wireless', 'Wireless') ], string="Communication Type", default='wired') specific_requirements = fields.Html(string="Specific Requirements") #CE Team Fields engineers_nos=fields.Integer(string="No of engineers required") no_of_days=fields.Integer(string="No of days") extra_cost_line_ids = fields.One2many('sos_extra_cost_lines', 'ref_id',copy=True) # mode_of_transport = fields.Selection([('car','🚗 Car'),('bus','🚌 Bus'),('train','🚂 Train'),('flight','đŸ›Šī¸ Flight')],string='Mode of Transport',default="train") # transport_expense = fields.Monetary(readonly=False,string="Transport", compute='_compute_transport_expense', store=True, currency_field='currency_id') # food_expense = fields.Monetary(readonly=False,string="Food", compute='_compute_food_expense', store=True, currency_field='currency_id') # stay_expense = fields.Monetary(readonly=False,string="Room Rent", compute='_compute_stay_expense', store=True, currency_field='currency_id') # local_expense = fields.Monetary(readonly=False,string="Local Conveyance", compute='_compute_local_expense', store=True, currency_field='currency_id') man_month_1to2_yrs_persons = fields.Integer(string="Man Month (Persons) 1 to 2 Yrs") man_month_2to3_yrs_persons = fields.Integer(string="Man Month (Persons) 2 to 3 Yrs") man_month_manager_persons = fields.Integer(string="Man Month (Persons) Manager Yrs") man_month_1to2_yrs_cost = fields.Monetary(string="Cost", currency_field='currency_id') man_month_2to3_yrs_cost = fields.Monetary(string="Cost", currency_field='currency_id') man_month_manager_cost = fields.Monetary(string="Cost", currency_field='currency_id') iandc_costing=fields.Monetary(readonly=False,string="I & C Costing",currency_field='currency_id',compute='_compute_iandc_expense') #FG Fields line_ids_fg_ups1 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 1",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups2 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 2",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups3 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 3",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups4 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 4",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups5 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 5",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups6 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 6",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups7 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 7",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups8 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups9 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups10 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 10",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups11 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 11",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups12 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 12",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups13 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 13",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups14 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 14",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups15 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 15",compute='_compute_line_ids_by_ups',store=False) merged_fg_html = fields.Html(string="FG (Merged)", compute="_compute_merged_fg_html", sanitize=False) merged_sfg_html = fields.Html(string="SFG (Merged)", compute="_compute_merged_sfg_html", sanitize=False) merged_material_html = fields.Html(string="Materials (Merged)", compute="_compute_merged_material_html", sanitize=False) merged_installation_kit_html = fields.Html(string="InstallationKit (Merged)", compute="_compute_merged_installation_kit_html", sanitize=False) merged_miscellaneous_html = fields.Html(string="Miscellaneous (Merged)", compute="_compute_merged_miscellaneous_html", sanitize=False) merged_spare_html = fields.Html(string="Spare (Merged)", compute="_compute_merged_spare_html", sanitize=False) #SFG Fields line_ids_sfg_ups1 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 1",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups2 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 2",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups3 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 3",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups4 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 4",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups5 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 5",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups6 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 6",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups7 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 7",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups8 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups9 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups10 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 10",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups11 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 11",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups12 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 12",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups13 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 13",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups14 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 14",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups15 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 15",compute='_compute_line_ids_by_ups',store=False) #Material Fields line_ids_material_ups1 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 1",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups2 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 2",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups3 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 3",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups4 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 4",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups5 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 5",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups6 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 6",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups7 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 7",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups8 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 8",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups9 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 9",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups10 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 10",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups11 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 11",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups12 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 12",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups13 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 13",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups14 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 14",compute='_compute_line_ids_by_ups',store=False,readonly=False) line_ids_material_ups15 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 15",compute='_compute_line_ids_by_ups',store=False,readonly=False) #Installation Kit Fields line_ids_installation_kit_ups1 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 1",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups2 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 2",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups3 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 3",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups4 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 4",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups5 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 5",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups6 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 6",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups7 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 7",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups8 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups9 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups10 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 10",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups11 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 11",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups12 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 12",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups13 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 13",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups14 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 14",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups15 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 15",compute='_compute_line_ids_by_ups',store=False) #Miscellaneous Kit Fields line_ids_miscellaneous_ups1 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 1",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups2 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 2",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups3 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 3",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups4 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 4",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups5 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 5",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups6 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 6",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups7 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 7",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups8 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups9 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups10 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 10",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups11 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 11",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups12 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 12",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups13 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 13",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups14 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 14",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups15 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 15",compute='_compute_line_ids_by_ups',store=False) #ups totals ups1_total = fields.Float(string="UPS 1 Total Cost",compute='_compute_ups_total',store=True) ups2_total = fields.Float(string="UPS 2 Total Cost", compute='_compute_ups_total', store=True) ups3_total = fields.Float(string="UPS 3 Total Cost", compute='_compute_ups_total', store=True) ups4_total = fields.Float(string="UPS 4 Total Cost", compute='_compute_ups_total', store=True) ups5_total = fields.Float(string="UPS 5 Total Cost", compute='_compute_ups_total', store=True) ups6_total = fields.Float(string="UPS 6 Total Cost", compute='_compute_ups_total', store=True) ups7_total = fields.Float(string="UPS 7 Total Cost", compute='_compute_ups_total', store=True) ups8_total = fields.Float(string="UPS 8 Total Cost", compute='_compute_ups_total', store=True) ups9_total = fields.Float(string="UPS 9 Total Cost", compute='_compute_ups_total', store=True) ups10_total = fields.Float(string="UPS 10 Total Cost", compute='_compute_ups_total', store=True) ups11_total = fields.Float(string="UPS 11 Total Cost", compute='_compute_ups_total', store=True) ups12_total = fields.Float(string="UPS 12 Total Cost", compute='_compute_ups_total', store=True) ups13_total = fields.Float(string="UPS 13 Total Cost", compute='_compute_ups_total', store=True) ups14_total = fields.Float(string="UPS 14 Total Cost", compute='_compute_ups_total', store=True) ups15_total = fields.Float(string="UPS 15 Total Cost", compute='_compute_ups_total', store=True) extra_lines_cost = fields.Monetary(string="Cost", compute='_compute_extra_lines_cost', store=True, currency_field='currency_id') packing_and_forwarding = fields.Monetary(string="Packing & Forwarding", currency_field='currency_id',store=True) additional_warranty = fields.Monetary(string="Additional Warranty", currency_field='currency_id',store=True) line_ids_spare_ups1 = fields.One2many('sos_proposal_line_spare_ups1','ref_id', string="Spare UPS 1") line_ids_spare_ups2 = fields.One2many('sos_proposal_line_spare_ups2', 'ref_id',string="Spare UPS 2") line_ids_spare_ups3 = fields.One2many('sos_proposal_line_spare_ups3','ref_id', string="Spare UPS 3") line_ids_spare_ups4 = fields.One2many('sos_proposal_line_spare_ups4', 'ref_id',string="Spare UPS 4") line_ids_spare_ups5 = fields.One2many('sos_proposal_line_spare_ups5','ref_id', string="Spare UPS 5") line_ids_spare_ups6 = fields.One2many('sos_proposal_line_spare_ups6', 'ref_id',string="Spare UPS 6") line_ids_spare_ups7 = fields.One2many('sos_proposal_line_spare_ups7','ref_id', string="Spare UPS 7") line_ids_spare_ups8 = fields.One2many('sos_proposal_line_spare_ups8','ref_id', string="Spare UPS 8") line_ids_spare_ups9 = fields.One2many('sos_proposal_line_spare_ups9','ref_id', string="Spare UPS 9") line_ids_spare_ups10 = fields.One2many('sos_proposal_line_spare_ups10','ref_id', string="Spare UPS 10") line_ids_spare_ups11 = fields.One2many('sos_proposal_line_spare_ups11','ref_id', string="Spare UPS 11") line_ids_spare_ups12 = fields.One2many('sos_proposal_line_spare_ups12','ref_id', string="Spare UPS 12") line_ids_spare_ups13 = fields.One2many('sos_proposal_line_spare_ups13','ref_id', string="Spare UPS 13") line_ids_spare_ups14 = fields.One2many('sos_proposal_line_spare_ups14','ref_id', string="Spare UPS 14") line_ids_spare_ups15 = fields.One2many('sos_proposal_line_spare_ups15','ref_id', string="Spare UPS 15") def _compute_merged_spare_html(self): for rec in self: # Collect lines from ups1..ups15 (skip models that don't exist) models = [f'sos_proposal_line_spare_ups{i}' for i in range(1, 16)] agg = defaultdict(float) # (component_id, uom, currency_id, unit_price) -> qty name_map, curr_map, price_map = {}, {}, {} for model in models: if model not in self.env: continue for l in self.env[model].search([('ref_id', '=', rec.id)]): unit_price = l.unit_price or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.component_id.id, l.uom, curr_id, unit_price) agg[key] += float(l.quantity or 0) if key not in name_map: # Use part number (fallback to component name if needed) name_map[key] = (getattr(l.component_id, 'part_no', False) or l.component_id.name or '') curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = unit_price rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_spare_html = "No Material items." continue def fmt_price(amount, currency): return format_amount(self.env, amount, currency) if currency else f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{key[1] or ''}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: rec.merged_spare_html = "No Material items." continue currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_spare_html = f""" {rows_html}
Material Name UoM Unit Price Total Qty Total Price
""" def _compute_merged_miscellaneous_html(self): for rec in self: lines = self.env['sos_proposal_miscellaneous_items'].search([('ref_id', '=', rec.id)]) # Group by (component, currency, cost) agg = defaultdict(float) name_map = {} curr_map = {} price_map = {} for l in lines: cost = l.cost or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.name, curr_id, cost) agg[key] += float(l.quantity or 0) if key not in name_map: name_map[key] = l.name or '' curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = cost rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_miscellaneous_html = "No Miscellaneous items." continue def fmt_price(amount, currency): if currency: return format_amount(self.env, amount, currency) return f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: # Skip rows with qty = 0 continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: # If all rows were skipped rec.merged_miscellaneous_html = "No Miscellaneous items." continue # Add grand total row currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_miscellaneous_html = f""" {rows_html}
Name Unit Price Total Qty Total Price
""" def _compute_merged_installation_kit_html(self): for rec in self: lines = self.env['sos_proposal_line_material_installation'].search([('ref_id', '=', rec.id)]) # Group by (component, uom, currency, unit_price) agg = defaultdict(float) name_map = {} curr_map = {} price_map = {} for l in lines: unit_price = l.unit_price or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.component_id.id, l.uom, curr_id, unit_price) agg[key] += float(l.quantity or 0) if key not in name_map: name_map[key] = l.component_id.part_no or '' curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = unit_price rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_installation_kit_html = "No Material items." continue def fmt_price(amount, currency): if currency: return format_amount(self.env, amount, currency) return f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: # Skip rows with qty = 0 continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{key[1] or ''}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: # If all rows were skipped rec.merged_installation_kit_html = "No Material items." continue # Add grand total row currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_installation_kit_html = f""" {rows_html}
Material Name UoM Unit Price Total Qty Total Price
""" def _compute_merged_material_html(self): for rec in self: lines = self.env['sos_proposal_boq_material'].search([('ref_id', '=', rec.id)]) # Group by (component, uom, currency, unit_price) agg = defaultdict(float) name_map = {} curr_map = {} price_map = {} for l in lines: unit_price = l.unit_price or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.component_id.id, l.uom, curr_id, unit_price) agg[key] += float(l.quantity or 0) if key not in name_map: name_map[key] = l.component_id.part_no or '' curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = unit_price rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_material_html = "No Material items." continue def fmt_price(amount, currency): if currency: return format_amount(self.env, amount, currency) return f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: # Skip rows with qty = 0 continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{key[1] or ''}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: # If all rows were skipped rec.merged_material_html = "No Material items." continue # Add grand total row currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_material_html = f""" {rows_html}
Material Name UoM Unit Price Total Qty Total Price
""" def _compute_merged_sfg_html(self): for rec in self: lines = self.env['sos_proposal_boq_sfg'].search([('ref_id', '=', rec.id)]) # Group by (component, uom, currency, unit_price) agg = defaultdict(float) name_map = {} curr_map = {} price_map = {} for l in lines: unit_price = l.unit_price or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.component_id.id, l.uom, curr_id, unit_price) agg[key] += float(l.quantity or 0) if key not in name_map: name_map[key] = l.component_id.name or '' curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = unit_price rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_sfg_html = "No SFG items." continue def fmt_price(amount, currency): if currency: return format_amount(self.env, amount, currency) return f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: # Skip rows with qty = 0 continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{key[1] or ''}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: # If all rows were skipped rec.merged_sfg_html = "No SFG items." continue # Add grand total row currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_sfg_html = f""" {rows_html}
SFG Name UoM Unit Price Total Qty Total Price
""" def _compute_merged_fg_html(self): for rec in self: lines = self.env['sos_proposal_boq_fg'].search([('ref_id', '=', rec.id)]) # Group by (component, uom, currency, unit_price) agg = defaultdict(float) name_map = {} curr_map = {} price_map = {} for l in lines: unit_price = l.unit_price or 0.0 curr_id = l.currency_id.id if l.currency_id else False key = (l.component_id.id, l.uom, curr_id, unit_price) agg[key] += float(l.quantity or 0) if key not in name_map: name_map[key] = l.component_id.name or '' curr_map[key] = l.currency_id if l.currency_id else False price_map[key] = unit_price rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower()) if not rows_sorted: rec.merged_fg_html = "No FG items." continue def fmt_price(amount, currency): if currency: return format_amount(self.env, amount, currency) return f"{amount:.2f}" total_sum = 0.0 rows_html = "" for key, qty in rows_sorted: if not qty: # Skip rows with qty = 0 continue total_price = qty * price_map[key] total_sum += total_price rows_html += ( f"" f"{name_map[key]}" f"{key[1] or ''}" f"{fmt_price(price_map[key], curr_map[key])}" f"{qty:.2f}" f"{fmt_price(total_price, curr_map[key])}" f"" ) if not rows_html: # If all rows were skipped rec.merged_fg_html = "No FG items." continue # Add grand total row currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False rows_html += ( f"" f"Grand Total:" f"{fmt_price(total_sum, currency_for_total)}" f"" ) rec.merged_fg_html = f""" {rows_html}
FG Name UoM Unit Price Total Qty Total Price
""" @api.model def create(self, vals): res = super().create(vals) if 'boq_submitted_by_name' in vals: res._trigger_recompute_on_target_model() elif 'acc_approved_by_name' in vals: res._trigger_recompute_on_target_model_acc() return res def write(self, vals): result = super().write(vals) if 'boq_submitted_by_name' in vals: self._trigger_recompute_on_target_model() elif 'acc_approved_by_name' in vals: self._trigger_recompute_on_target_model_acc() return result def _trigger_recompute_on_target_model(self): related_records = self.env['sos_proposal_customer_requirement'].search([('proposal_id', '=', self.proposal_id.id)]) for rec in related_records: rec._compute_boq_submitted_by() def _trigger_recompute_on_target_model_acc(self): related_records = self.env['sos_proposal_customer_requirement'].search([('proposal_id', '=', self.proposal_id.id)]) for rec in related_records: rec._compute_acc_costing_submitted_by() # @api.depends('no_of_days') # def _compute_local_expense(self): # for rec in self: # rec.local_expense = rec.no_of_days * 500 # @api.depends('no_of_days') # def _compute_stay_expense(self): # for rec in self: # rec.stay_expense = rec.no_of_days * 2500 # @api.depends('no_of_days') # def _compute_food_expense(self): # for rec in self: # rec.food_expense = rec.no_of_days * 600 # @api.depends('no_of_days') # def _compute_transport_expense(self): # for rec in self: # rec.transport_expense = 5000 @api.depends('no_of_days','man_month_1to2_yrs_persons','man_month_2to3_yrs_persons','man_month_manager_persons','man_month_1to2_yrs_cost','man_month_2to3_yrs_cost','man_month_manager_cost') def _compute_iandc_expense(self): for rec in self: rec.iandc_costing = ((rec.man_month_1to2_yrs_persons * rec.man_month_1to2_yrs_cost) + (rec.man_month_2to3_yrs_persons * rec.man_month_2to3_yrs_cost) + (rec.man_month_manager_persons * rec.man_month_manager_cost)) * rec.no_of_days @api.depends('extra_cost_line_ids.cost') def _compute_extra_lines_cost(self): for record in self: record.extra_lines_cost = sum(line.cost for line in record.extra_cost_line_ids) @api.depends('iandc_costing','warranty_cost', 'total_cost','margin','extra_lines_cost','packing_and_forwarding','additional_warranty') def _compute_final_cost(self): for rec in self: rec.final_cost = rec.warranty_cost + rec.total_cost + rec.margin + rec.extra_lines_cost + rec.packing_and_forwarding + rec.additional_warranty + rec.iandc_costing @api.depends('total_cost', 'warranty_percentage') def _compute_warranty(self): for rec in self: base = rec.total_cost or 0.0 percent = rec.warranty_percentage or 0 rec.warranty_cost = (percent / 100.0) * base @api.depends('margin_per_battery', 'number_of_batteries') def _compute_margin(self): for rec in self: if rec.number_of_batteries: rec.margin= rec.margin_per_battery * rec.number_of_batteries else: rec.margin = 0.0 @api.depends('final_cost', 'number_of_batteries') def _compute_final_cost_per_battery(self): for rec in self: if rec.number_of_batteries: rec.final_cost_per_battery = rec.final_cost / rec.number_of_batteries else: rec.final_cost_per_battery = 0.0 @api.depends( 'line_ids_fg.total_price', 'line_ids_fg.ups_index', 'line_ids_fg.production_cost', 'line_ids_sfg.total_price', 'line_ids_sfg.ups_index', 'line_ids_sfg.production_cost', 'line_ids_material.total_price', 'line_ids_material.ups_index', 'line_ids_material.production_cost', 'line_ids_installation_kit.total_price', 'line_ids_installation_kit.ups_index', 'line_ids_installation_kit.production_cost', 'line_ids_miscellaneous.total_price', 'line_ids_miscellaneous.ups_index', 'line_ids_miscellaneous.production_cost', 'line_ids_spare_ups1.total_price', 'line_ids_spare_ups1.production_cost', 'line_ids_spare_ups2.total_price', 'line_ids_spare_ups2.production_cost', 'line_ids_spare_ups3.total_price', 'line_ids_spare_ups3.production_cost', 'line_ids_spare_ups4.total_price', 'line_ids_spare_ups4.production_cost', 'line_ids_spare_ups5.total_price', 'line_ids_spare_ups5.production_cost', 'line_ids_spare_ups6.total_price', 'line_ids_spare_ups6.production_cost', 'line_ids_spare_ups7.total_price', 'line_ids_spare_ups7.production_cost', 'line_ids_spare_ups8.total_price', 'line_ids_spare_ups8.production_cost', 'line_ids_spare_ups9.total_price', 'line_ids_spare_ups9.production_cost', 'line_ids_spare_ups10.total_price', 'line_ids_spare_ups10.production_cost', 'line_ids_spare_ups11.total_price', 'line_ids_spare_ups11.production_cost', 'line_ids_spare_ups12.total_price', 'line_ids_spare_ups12.production_cost', 'line_ids_spare_ups13.total_price', 'line_ids_spare_ups13.production_cost', 'line_ids_spare_ups14.total_price', 'line_ids_spare_ups14.production_cost', 'line_ids_spare_ups15.total_price', 'line_ids_spare_ups15.production_cost' ) def _compute_ups_total(self): for rec in self: for i in range(1, 16): total = 0 for field_name in [ 'line_ids_fg', 'line_ids_sfg', 'line_ids_material', 'line_ids_installation_kit', 'line_ids_miscellaneous', f'line_ids_spare_ups{i}', ]: lines = getattr(rec, field_name) total += sum( line.total_price for line in lines if line.ups_index == i and line.production_cost ) setattr(rec, f'ups{i}_total', total) @api.depends( 'line_ids_fg.ups_index', 'line_ids_sfg.ups_index', 'line_ids_material.ups_index', 'line_ids_installation_kit.ups_index', 'line_ids_miscellaneous.ups_index' ) def _compute_line_ids_by_ups(self): for rec in self: rec.line_ids_fg_ups1 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 1) rec.line_ids_fg_ups2 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 2) rec.line_ids_fg_ups3 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 3) rec.line_ids_fg_ups4 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 4) rec.line_ids_fg_ups5 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 5) rec.line_ids_fg_ups6 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 6) rec.line_ids_fg_ups7 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 7) rec.line_ids_fg_ups8 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 8) rec.line_ids_fg_ups9 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 9) rec.line_ids_fg_ups10 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 10) rec.line_ids_fg_ups11 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 11) rec.line_ids_fg_ups12 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 12) rec.line_ids_fg_ups13 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 13) rec.line_ids_fg_ups14 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 14) rec.line_ids_fg_ups15 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 15) rec.line_ids_sfg_ups1 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 1) rec.line_ids_sfg_ups2 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 2) rec.line_ids_sfg_ups3 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 3) rec.line_ids_sfg_ups4 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 4) rec.line_ids_sfg_ups5 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 5) rec.line_ids_sfg_ups6 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 6) rec.line_ids_sfg_ups7 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 7) rec.line_ids_sfg_ups8 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 8) rec.line_ids_sfg_ups9 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 9) rec.line_ids_sfg_ups10 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 10) rec.line_ids_sfg_ups11 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 11) rec.line_ids_sfg_ups12 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 12) rec.line_ids_sfg_ups13 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 13) rec.line_ids_sfg_ups14 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 14) rec.line_ids_sfg_ups15 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 15) rec.line_ids_material_ups1 = rec.line_ids_material.filtered(lambda l: l.ups_index == 1) rec.line_ids_material_ups2 = rec.line_ids_material.filtered(lambda l: l.ups_index == 2) rec.line_ids_material_ups3 = rec.line_ids_material.filtered(lambda l: l.ups_index == 3) rec.line_ids_material_ups4 = rec.line_ids_material.filtered(lambda l: l.ups_index == 4) rec.line_ids_material_ups5 = rec.line_ids_material.filtered(lambda l: l.ups_index == 5) rec.line_ids_material_ups6 = rec.line_ids_material.filtered(lambda l: l.ups_index == 6) rec.line_ids_material_ups7 = rec.line_ids_material.filtered(lambda l: l.ups_index == 7) rec.line_ids_material_ups8 = rec.line_ids_material.filtered(lambda l: l.ups_index == 8) rec.line_ids_material_ups9 = rec.line_ids_material.filtered(lambda l: l.ups_index == 9) rec.line_ids_material_ups10 = rec.line_ids_material.filtered(lambda l: l.ups_index == 10) rec.line_ids_material_ups11 = rec.line_ids_material.filtered(lambda l: l.ups_index == 11) rec.line_ids_material_ups12 = rec.line_ids_material.filtered(lambda l: l.ups_index == 12) rec.line_ids_material_ups13 = rec.line_ids_material.filtered(lambda l: l.ups_index == 13) rec.line_ids_material_ups14 = rec.line_ids_material.filtered(lambda l: l.ups_index == 14) rec.line_ids_material_ups15 = rec.line_ids_material.filtered(lambda l: l.ups_index == 15) rec.line_ids_installation_kit_ups1 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 1) rec.line_ids_installation_kit_ups2 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 2) rec.line_ids_installation_kit_ups3 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 3) rec.line_ids_installation_kit_ups4 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 4) rec.line_ids_installation_kit_ups5 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 5) rec.line_ids_installation_kit_ups6 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 6) rec.line_ids_installation_kit_ups7 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 7) rec.line_ids_installation_kit_ups8 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 8) rec.line_ids_installation_kit_ups9 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 9) rec.line_ids_installation_kit_ups10 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 10) rec.line_ids_installation_kit_ups11 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 11) rec.line_ids_installation_kit_ups12 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 12) rec.line_ids_installation_kit_ups13 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 13) rec.line_ids_installation_kit_ups14 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 14) rec.line_ids_installation_kit_ups15 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 15) rec.line_ids_miscellaneous_ups1 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 1) rec.line_ids_miscellaneous_ups2 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 2) rec.line_ids_miscellaneous_ups3 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 3) rec.line_ids_miscellaneous_ups4 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 4) rec.line_ids_miscellaneous_ups5 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 5) rec.line_ids_miscellaneous_ups6 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 6) rec.line_ids_miscellaneous_ups7 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 7) rec.line_ids_miscellaneous_ups8 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 8) rec.line_ids_miscellaneous_ups9 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 9) rec.line_ids_miscellaneous_ups10 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 10) rec.line_ids_miscellaneous_ups11 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 11) rec.line_ids_miscellaneous_ups12 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 12) rec.line_ids_miscellaneous_ups13 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 13) rec.line_ids_miscellaneous_ups14 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 14) rec.line_ids_miscellaneous_ups15 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 15) @api.model def create(self, vals): record = super().create(vals) if vals.get('proposal_id'): record._generate_boq_lines_from_proposal() return record @api.onchange('proposal_id') def _onchange_proposal_id(self): if not self.proposal_id: return if self.line_ids_fg or self.line_ids_material or self.line_ids_sfg: return self.customer_name = self.proposal_id.customer_name self.location = self.proposal_id.location self.no_of_electrical_panel = self.proposal_id.no_of_electrical_panel self.number_of_batteries = self.proposal_id.number_of_batteries self.number_of_ups = self.proposal_id.number_of_ups self.products = self.proposal_id.products self.communication_type = self.proposal_id.communication_type self.specific_requirements = self.proposal_id.specific_requirements multiplier = max(1, math.ceil(self.proposal_id.number_of_batteries / 20)) if self.proposal_id.number_of_batteries < 100: self.engineers_nos = 1 self.no_of_days = multiplier else: self.engineers_nos = 2 self.no_of_days = multiplier / 2 packing_calculation = 1200 packing_kg_12V = 100 * self.proposal_id.number_of_ups direction = self.proposal_id.direction if direction == "North": forwarding_calculation = 20 * packing_kg_12V elif direction == "West": forwarding_calculation = 19 * packing_kg_12V elif direction == "East": forwarding_calculation = 23 * packing_kg_12V else: forwarding_calculation = 13 * packing_kg_12V base_amount = 1.20 * (packing_calculation + forwarding_calculation) self.packing_and_forwarding = base_amount * 1.18 # Clear all lines self.line_ids_fg = [(5, 0, 0)] self.line_ids_sfg = [(5, 0, 0)] self.line_ids_material = [(5, 0, 0)] self.line_ids_installation_kit = [(5, 0, 0)] self.line_ids_miscellaneous = [(5, 0, 0)] self._generate_boq_lines_from_proposal() def _generate_boq_lines_from_proposal(self): if not self.proposal_id: return record = self.env['sos_deliverables_config'].search([ ('fg_name', '=', self.products), ('communication_type', '=', self.communication_type) ], limit=1) if record and self.number_of_ups: fg_lines = [] sfg_lines = [] material_lines = [] install_kit_lines = [] misc_lines = [] for ups_index in range(1, self.number_of_ups + 1): for line in record.fg_ids: single_set_qty = 1 if line.item_type == 'Master Panel': single_set_qty = 1 elif line.item_type == 'CT Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: number_of_strings_per_battery = matching_ups_line.number_of_strings_per_battery single_set_qty = number_of_strings_per_battery ct_module = ((matching_ups_line.ups_capacity_kva * 1000) / (12 * matching_ups_line.number_of_batteries)) / 10 if 0 <= ct_module < 100: material_code="MDS070" elif 100 <= ct_module < 200: material_code="MDS071" elif 200 <= ct_module < 300: material_code="MDS069" else: material_code="MDS040" material_record=self.env['sos_material'].search([('material_code', '=', material_code)],limit=1) material_lines.append((0, 0, { 'component_id': material_record.id, 'uom': material_record.uom, 'singet_set_qty':single_set_qty, 'unit_price': material_record.unit_price, 'description': material_record.description, 'ups_index': ups_index, 'production_cost':True })) elif line.item_type == 'Slave Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: single_set_qty = math.ceil((matching_ups_line.number_of_batteries)/4) * matching_ups_line.number_of_strings_per_battery name_lower = (line.component_id.name or "").lower() is_electrical_panel = "electrical panel" in name_lower is_panel_exceeding = self.proposal_id.no_of_electrical_panel < ups_index fg_lines.append((0, 0, { 'component_id': line.component_id.id, 'uom': line.uom, 'unit_price': 0.00 if is_panel_exceeding and is_electrical_panel else line.component_id.unit_price, 'description': line.description, 'item_type': line.item_type, 'total_set': 0 if is_panel_exceeding and is_electrical_panel else 1, 'singet_set_qty': 0 if is_panel_exceeding and is_electrical_panel else single_set_qty, 'production_cost': line.add_production_cost, 'ups_index': ups_index })) for line in record.sfg_ids: if line.item_type == 'Master Panel': single_set_qty = 1 elif line.item_type == 'CT Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: number_of_strings_per_battery = matching_ups_line.number_of_strings_per_battery single_set_qty = number_of_strings_per_battery # example logic elif line.item_type == 'Slave Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: single_set_qty = math.ceil((matching_ups_line.number_of_batteries)/4) * matching_ups_line.number_of_strings_per_battery sfg_lines.append((0, 0, { 'component_id': line.component_id.id, 'uom': line.uom, 'unit_price': line.component_id.unit_price, 'description': line.description, 'item_type': line.item_type, 'singet_set_qty': single_set_qty, 'production_cost': line.add_production_cost, 'ups_index': ups_index })) for line in record.material_ids: if line.item_type == 'Internet Module' and self.proposal_id.internet_connectivity != 'yes': continue if line.item_type == 'Master Panel': single_set_qty = 1 * line.quantity elif line.item_type == 'CT Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: number_of_strings_per_battery = matching_ups_line.number_of_strings_per_battery single_set_qty = number_of_strings_per_battery * line.quantity elif line.item_type == 'Slave Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: single_set_qty = (math.ceil((matching_ups_line.number_of_batteries)/4) * matching_ups_line.number_of_strings_per_battery) * line.quantity material_lines.append((0, 0, { 'component_id': line.component_id.id, 'uom': line.uom, 'unit_price': line.component_id.unit_price, 'description': line.description, 'item_type': line.item_type, 'singet_set_qty': single_set_qty, 'production_cost': line.add_production_cost, 'ups_index': ups_index })) for line in record.installation_kit_ids: if line.item_type == 'Master Panel': single_set_qty = 1 * line.quantity elif line.item_type == 'CT Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: number_of_strings_per_battery = matching_ups_line.number_of_strings_per_battery single_set_qty = number_of_strings_per_battery * line.quantity elif line.item_type == 'Slave Module': matching_ups_line = self.proposal_id.ups_line_ids.filtered(lambda l: l.ups_index == ups_index) if matching_ups_line: single_set_qty = (math.ceil((matching_ups_line.number_of_batteries)/4) * matching_ups_line.number_of_strings_per_battery) * line.quantity install_kit_lines.append((0, 0, { 'component_id': line.component_id.id, 'uom': line.uom, 'unit_price': line.component_id.unit_price, 'description': line.description, 'item_type': line.item_type, 'singet_set_qty': single_set_qty, 'production_cost': line.add_production_cost, 'ups_index': ups_index })) misc_lines += [(0, 0, { 'name': line.name, 'cost': line.cost, 'quantity': line.quantity, 'ups_index': ups_index }) for line in record.miscellaneous_ids] self.write({ 'line_ids_fg': fg_lines, 'line_ids_sfg': sfg_lines, 'line_ids_material': material_lines, 'line_ids_installation_kit': install_kit_lines, 'line_ids_miscellaneous': misc_lines }) def action_report_btn(self): try: action = self.env.ref("sos_sales.action_report_proposal_boq").report_action(self) return action except ValueError as e: print(f"Failed to find report action: {e}") @api.depends('ups1_total','ups2_total','ups3_total','ups4_total','ups5_total','ups6_total','ups7_total','ups8_total','ups9_total','ups10_total') def _compute_total_cost(self): for record in self: record.total_cost = record.ups1_total + record.ups2_total + record.ups3_total + record.ups4_total + record.ups5_total + record.ups6_total + record.ups7_total + record.ups8_total + record.ups9_total + record.ups10_total @api.depends('line_ids_miscellaneous.cost') def _compute_total_miscellaneous_cost(self): for record in self: record.total_miscellaneous_cost = sum(line.total_price for line in record.line_ids_miscellaneous) @api.depends('line_ids_installation_kit.unit_price') def _compute_total_installation_material_cost(self): for record in self: record.total_installation_material_cost = sum(line.total_price for line in record.line_ids_installation_kit) @api.depends('line_ids_material.unit_price') def _compute_total_material_cost(self): for record in self: record.total_material_cost = sum(line.total_price for line in record.line_ids_material) @api.depends('line_ids_sfg.unit_price') def _compute_total_sfg_cost(self): for record in self: record.total_sfg_cost = sum(line.total_price for line in record.line_ids_sfg) @api.depends('line_ids_fg.unit_price') def _compute_total_fg_cost(self): for record in self: record.total_fg_cost = sum(line.total_price for line in record.line_ids_fg) def action_ce_esign_btn(self): body_html = f"""

Below BOQ is waiting for your updation.

Customer Name: {self.customer_name or ''}

Location: {self.location or ''}

Number of Batteries: {self.number_of_batteries or ''}

""" sequence_util = self.env['sos_common_scripts'] sequence_util.send_group_email( self.env, 'sos_proposal_boq', self.id, "deenalaura.m@sosaley.in", f"Proposal System - BOQ Submitted for {self.customer_name}", body_html, 'sos_inventory.sos_finance_user' ) return sequence_util.action_assign_signature( self, 'boq_submitted_by_name', 'boq_submitted_by_approved_on' ) def action_acc_esign_btn(self): sequence_util = self.env['sos_common_scripts'] body_html = """

Below Proposal is waiting for your Updation

""" req_submitted_by = self.env['sos_proposal_customer_requirement'].search([ ('proposal_id', '=', self.proposal_id.proposal_id) ], limit=1) # Send email only if login exists if req_submitted_by and req_submitted_by.requirement_submitted_by_name and req_submitted_by.requirement_submitted_by_name.login: sequence_util.send_direct_email( self.env, "sos_proposal_boq", self.id, req_submitted_by.requirement_submitted_by_name.login, f"Costing Done - {self.proposal_id.proposal_id}", body_html ) # Assign signature return sequence_util.action_assign_signature( self, 'acc_approved_by_name', 'acc_approved_on' ) class SOS_Proposal_BOQ_Material(models.Model): _name = 'sos_proposal_boq_material' _description = 'Proposal BOQ Material Lines' ref_id = fields.Many2one('sos_proposal_boq', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'), ('Packs', 'Packs'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",store=True) unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") production_cost = fields.Boolean(string="Include in Costing") ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price','quantity') def _compute_total_price(self): for record in self: record.total_price = record.unit_price * record.quantity class SOS_Proposal_BOQ_SFG(models.Model): _name = 'sos_proposal_boq_sfg' _description = 'Proposal BOQ SFG Lines' ref_id = fields.Many2one('sos_proposal_boq', string="SFG", ondelete="cascade") currency_id = fields.Many2one('res.currency', string='Currency') component_id = fields.Many2one('sos_sfg', string="SFG Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") sfg_code = fields.Char(related="component_id.sfg_code",string="SFG Code") sfg_name = fields.Char(related="component_id.name",string="SFG Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",store=True) unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") production_cost = fields.Boolean(string="Include in Costing") ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): """ Set the initial value of `unit_price` when `component_id` is changed. """ for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price','quantity') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class SOS_Proposal_BOQ_FG(models.Model): _name = 'sos_proposal_boq_fg' _description = 'Proposal BOQ FG Lines' ref_id = fields.Many2one('sos_proposal_boq', string="FG", ondelete="cascade") currency_id = fields.Many2one('res.currency', string='Currency') component_id = fields.Many2one('sos_fg',string="FG Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") fg_code = fields.Char(related="component_id.fg_code",string="FG Code") fg_name = fields.Char(related="component_id.name",string="FG Name") quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",store=True) singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") production_cost = fields.Boolean(string="Include in Costing") ups_index = fields.Integer(string="UPS Index",store=True) @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price','quantity') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_proposal_MiscellaneousCost(models.Model): _name = 'sos_proposal_miscellaneous_items' _description = 'Miscellaneous Items' ref_id = fields.Many2one('sos_proposal_boq', string="Miscellaneous", ondelete="cascade") name = fields.Char(string='Name') cost = fields.Float(string='Cost') quantity = fields.Integer(string="Quantity") currency_id = fields.Many2one('res.currency', string='Currency') total_price = fields.Monetary(string="Total", currency_field='currency_id',compute="_compute_total_price") ups_index = fields.Integer(string="UPS Index",store=True) production_cost = fields.Boolean(string="Include in Costing",default=True) @api.depends('cost','quantity') def _compute_total_price(self): for record in self: record.total_price = record.cost * record.quantity class sos_proposal_Material_installationkit(models.Model): _name = 'sos_proposal_line_material_installation' _description = 'Installation Kit Lines' ref_id = fields.Many2one('sos_proposal_boq', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") production_cost = fields.Boolean(string="Include in Costing") ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price','quantity','production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_proposal_Material_installationkit(models.Model): _name = 'sos_proposal_line_spare' _description = 'Spare Lines' ref_id = fields.Many2one('sos_proposal_boq', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing") ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price','quantity') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_extra_cost_lines(models.Model): _name = 'sos_extra_cost_lines' _description = 'Extra Lines' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") field_name = fields.Char(string="Name") currency_id = fields.Many2one( 'res.currency', string='Currency', default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False ) cost = fields.Monetary(string="Cost", currency_field='currency_id', store=True) class sos_spare_material1(models.Model): _name = 'sos_proposal_line_spare_ups1' _description = 'Spare Material 1' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material2(models.Model): _name = 'sos_proposal_line_spare_ups2' _description = 'Spare Material 2' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material3(models.Model): _name = 'sos_proposal_line_spare_ups3' _description = 'Spare Material 3' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material4(models.Model): _name = 'sos_proposal_line_spare_ups4' _description = 'Spare Material 4' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material5(models.Model): _name = 'sos_proposal_line_spare_ups5' _description = 'Spare Material 5' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material6(models.Model): _name = 'sos_proposal_line_spare_ups6' _description = 'Spare Material 6' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material7(models.Model): _name = 'sos_proposal_line_spare_ups7' _description = 'Spare Material 7' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material8(models.Model): _name = 'sos_proposal_line_spare_ups8' _description = 'Spare Material 8' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material9(models.Model): _name = 'sos_proposal_line_spare_ups9' _description = 'Spare Material 9' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material10(models.Model): _name = 'sos_proposal_line_spare_ups10' _description = 'Spare Material 10' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material11(models.Model): _name = 'sos_proposal_line_spare_ups11' _description = 'Spare Material 11' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material12(models.Model): _name = 'sos_proposal_line_spare_ups12' _description = 'Spare Material 12' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material13(models.Model): _name = 'sos_proposal_line_spare_ups13' _description = 'Spare Material 13' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material14(models.Model): _name = 'sos_proposal_line_spare_ups14' _description = 'Spare Material 14' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00 class sos_spare_material15(models.Model): _name = 'sos_proposal_line_spare_ups15' _description = 'Spare Material 15' ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") material_name = fields.Char(related="component_id.part_no",string="Material Name") singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) total_set = fields.Integer(string="Total Set",default=1) quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") total_price = fields.Monetary(string="Total",compute="_compute_total_price") description = fields.Char(string="Description") production_cost = fields.Boolean(string="Include in Costing",default=True) ups_index = fields.Integer(string="UPS Index",store=True) @api.onchange('component_id') def _onchange_component_id(self): for record in self: if record.component_id: record.unit_price = record.component_id.unit_price @api.depends('singet_set_qty','total_set') def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set @api.depends('unit_price', 'quantity', 'production_cost') def _compute_total_price(self): for record in self: if record.production_cost: record.total_price = record.unit_price * record.quantity else: record.total_price = 0.00