from odoo import models, fields, api from odoo.exceptions import UserError from datetime import date,datetime class FIR_BRR(models.Model): _name = 'sos_fir_brr' _description = 'Batch Release Report' _rec_name='fir_no' _order = 'id desc' fir_no = fields.Char(string="BRR No",default=lambda self: self._generate_id(),readonly= True, required= True) fir_date = fields.Date(string="BRR Date") fg_name = fields.Many2one('sos_fg', string='FG Name') product_name = fields.Char(related="fg_name.name", string='Product Name',readonly=True) plan_ref_no = fields.Many2one('sos_fg_plan', string='Indent Ref No') batch_size = fields.Integer(string="Batch Size / Received Quantity") batch_No = fields.Char(string="Batch No") mfg_date = fields.Char(string="Manufacturing Date") sampling_size = fields.Char(string="Sampling Size") serial_no_line_ids = fields.One2many('sos_brr_serial_no_lines', 'ref_id',copy=True) calibration_line_ids = fields.One2many('sos_calibration_devices_fir', 'ref_id',copy=True) testing_parameter_line_ids = fields.One2many('sos_fir_brr_line', 'ref_line_id',copy=True) approved_qty = fields.Integer(string="Approved Quantity") rejected_qty = fields.Integer(string="Rejected Quantity") rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True) rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display') qc_by_name = fields.Many2one('res.users', string='QC Tested&Provided by Sign') qc_by_image = fields.Image(related="qc_by_name.signature_image",string='Prepared by Sign',readonly=True) qc_tested_on = fields.Date(string="Approved On") reworked_count = fields.Integer(string="Reworked Count",default=0) qa_by_name = fields.Many2one('res.users', string='QA by Sign') qa_by_image = fields.Image(related="qa_by_name.signature_image",string='Prepared by Sign',readonly=True) qa_tested_on = fields.Datetime(string="Approved On") ppm = fields.Integer(string="PPM",compute="_compute_ppm") stores_received_by = fields.Many2one('res.users', string='Store Received by Sign') stores_received_image = fields.Image(related="stores_received_by.signature_image",string='Stores Received by Sign',readonly=True) stores_received_on = fields.Date(string="Stores Received On") ncmr_ref = fields.Many2one('sos_ncmr',string="NCMR Reference (If any Rejected)") def action_report_brr_btn(self): try: action = self.env.ref("sos_inventory.action_report_brr").report_action(self) return action except ValueError as e: print(f"Failed to find report action: {e}") @api.depends('batch_size', 'rejected_qty') def _compute_ppm(self): for record in self: if record.rejected_qty != 0: record.ppm = (record.rejected_qty / record.batch_size) * 10**6 else: record.ppm = 0 @api.depends('rejection_percentage') def _compute_rejected_percentage_display(self): for record in self: record.rejection_percentage_display = "{:.2f}%".format(record.rejection_percentage) @api.depends('batch_size', 'rejected_qty') def _compute_rejected_percentage(self): for record in self: if record.batch_size > 0: record.rejection_percentage = (record.rejected_qty / record.batch_size) * 100 else: record.rejection_percentage = 0 def action_qc_esign_btn(self): ncmr_record = False sequence_util = self.env['sos_common_scripts'] ncmr_id = sequence_util.generate_sequence('sos_ncmr', 'NCMR', 'ncmr_no') if self.rejected_qty > 0: ncmr_record = self.env['sos_ncmr'].create({ 'ncmr_no': ncmr_id, 'fg_option':True, 'material_option':False, 'sfg_option':False, 'batch_no':self.batch_No, 'rejected_qty':self.rejected_qty, 'fg_name': self.fg_name.id, 'fg_incoming_doc_ref':self.id, 'department':'Quality Control' }) if ncmr_record: self.ncmr_ref = ncmr_record.id ncmr_body_html = f"""

Below NCMR is waiting for your Inspection

""" sequence_util.send_group_email(self.env,'sos_ncmr',ncmr_id,"deenalaura.m@sosaley.in","NCMR Inspection Pending",ncmr_body_html,'sos_inventory.sos_qc_user') # Email part body_html = f"""

Below Batch Release Report is waiting for your Approval

""" sequence_util.send_group_email(self.env,"sos_fir_brr",self.id,"deenalaura.m@sosaley.in","BRR Approval Request",body_html,'sos_inventory.sos_qa_user') # Email part ends return sequence_util.action_assign_signature( self, 'qc_by_name', 'qc_tested_on' ) def action_qa_esign_btn(self): # Email part body_html = f"""

Below FIR is waiting for your Approval

""" send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,"sos_fir_brr",self.id,"deenalaura.m@sosaley.in","BRR Approval Request",body_html,'sos_inventory.sos_scg_group_user') # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( self, 'qa_by_name', 'qa_tested_on' ) def action_stores_esign_btn(self): if self.plan_ref_no: # Production Status sos_record = self.env['sos_production_plan'].search([ ('fg_name', '=', self.fg_name.id), ('plan_ref_no', '=', self.plan_ref_no.plan_ref_no) ], limit=1) sequence_util = self.env['sos_common_scripts'] week_number = sequence_util.calculate_week_number( sos_record.indent_start_date , sos_record.target_date , date.today() ) field_name = f'qc_week_{week_number}' fgplan_field_name = f'planned_week_{week_number}' # FG Plan update fg_plan_record = self.env['sos_fg_plan_line'].search([ ('fg_name', '=', self.fg_name.id) ], limit=1) if fg_plan_record: current_value = getattr(fg_plan_record, fgplan_field_name, 0) fg_plan_record.write({fgplan_field_name: current_value + self.approved_qty}) if sos_record: current_value = getattr(sos_record, field_name, 0) sos_record.write({field_name: current_value + self.approved_qty}) # Production Status Ends sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( self, 'stores_received_by', 'stores_received_on', 'sos_inventory.sos_scg_group_user' ) approved_qty = self.approved_qty if approved_qty > 0: current_qty = self.fg_name.inhand_stock_qty new_qty = current_qty + approved_qty self.fg_name.inhand_stock_qty = new_qty self.env['sos_fg_transaction_history'].create({ 'ref_id': self.fg_name.id, 'fir_no': self.id, 'component_id': self.fg_name.id, 'quantity': approved_qty, 'action': 'in', }) def _generate_id(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_fir_brr','BRR', 'fir_no') @api.onchange('fg_name') def _onchange_fg_name(self): if self.fg_name: self._load_testing_parameters() @api.model def create(self, vals): record = super(FIR_BRR, self).create(vals) if record.fg_name: record._load_testing_parameters() return record def write(self, vals): result = super(FIR_BRR, self).write(vals) if 'fg_name' in vals: self._load_testing_parameters() return result def _load_testing_parameters(self): if self.fg_name: testing_parameters = self.env['sos_testing_parameters'].search([('fg_name', '=', self.fg_name.id)]) if not testing_parameters: raise UserError('No testing parameters found for this FG.') # Clear any existing lines lines = [(5, 0, 0)] sorted_parameters = testing_parameters.parameter_ids.sorted(key=lambda param: param.sequence) # Append the sorted parameters for param in sorted_parameters: lines.append((0, 0, { 'testing_parameter': param.id, 'sequence': param.sequence, 'specification': param.specification, 'results': param.results, 'inspection_decision':param.inspection_decision })) # Set the sorted lines to testing_parameter_line_ids self.testing_parameter_line_ids = lines class FIR_BRR_Line(models.Model): _name = 'sos_fir_brr_line' _description = 'Batch Release Report Line Items' ref_line_id = fields.Many2one('sos_fir_brr', ondelete="cascade") sequence = fields.Integer(string="sequence") testing_parameter = fields.Many2one('sos_parameter', string='Testing Parameter') sampled_qty = fields.Integer(string="Sampled Quantity") accepted_qty = fields.Integer(string="Accepted Quantity") rejected_qty = fields.Integer(string="Rejected Quantity") remarks = fields.Text(string="Remarks") inspection_decision = fields.Selection([('PASS','PASS'),('FAIL','FAIL')],string="Inspection Decision") specification = fields.Char(string="Specification") results = fields.Text(string="Results") class Calibration_devices(models.Model): _name = 'sos_calibration_devices_fir' _description = 'Calibartion Devices List' ref_id = fields.Many2one('sos_fir_brr', ondelete="cascade") calibration_device = fields.Many2one('sos_calibration_devices',string="Equipment Name", required=True) identification_No = fields.Char(string="Identification No",related="calibration_device.identification_no") certification_No = fields.Char(string="Certification No",related="calibration_device.certification_no") calibrated_date = fields.Date(string="Calibrated Date",related="calibration_device.calibrated_on") due_date = fields.Date(string="Due Date",related="calibration_device.calibrated_due") class FIR_BRR_serial_no_Lines(models.Model): _name = 'sos_brr_serial_no_lines' _description = 'Serial No Line Items' ref_id = fields.Many2one('sos_fir_brr', ondelete="cascade") serial_no = fields.Char(string="Serial No") inspection_decision = fields.Selection([('PASS','PASS'),('FAIL','FAIL')],string="Inspection Decision",default="PASS")