# -*- coding: utf-8 -*- from odoo import models, fields, api from datetime import datetime from odoo.exceptions import UserError class SOS_IR(models.Model): _name = 'sos_ir' _description = 'Inward Register' _rec_name = 'ir_no' _order = 'received_date desc, id desc' ir_no=fields.Char(string="Inward Reference No",default=lambda self: self._generate_id()) supplier_name = fields.Many2one('sos_suppliers', string="Supplier Name") supplier_address = fields.Text(related='supplier_name.address', string="Supplier Address") service_provider_name = fields.Many2one('sos_service_providers', string="Service Provider Name") service_provider_address = fields.Char(related='service_provider_name.address', string="Service Provider Address") po_no = fields.Many2one( 'sos_po', string="P.O No", domain="[('po_status', '=', 'open'), ('supplier_name', '=', supplier_name)]" ) wo_no = fields.Many2one( 'sos_wo', string="W.O No", domain="[('wo_status', '=', 'open'), ('supplier_name', '=', service_provider_name)]" ) wo_no_inhouse = fields.Many2one( 'sos_wo', string="W.O No", domain="[('wo_status', '=', 'open'), ('wo_planned_at', '=', 'inhouse')]" ) dc_no = fields.Many2one('sos_dc',string="DC No/Invoice No") dc_date = fields.Datetime(string="DC Date/Invoice Date") dc_no_char = fields.Char(string="DC No/Invoice No") received_date = fields.Date(string="Received Date",default=fields.Date.today) receiving_dept = fields.Many2one('sos_departments',string="Receiving Department") receiving_by = fields.Many2one('res.users', string='Received By') parcel_count = fields.Char(string="No of Bags/Barrels/Rolls/Boxes") received_goods_type = fields.Selection([ ('Materials', 'Materials'), ('SFG', 'SFG'), ('FG', 'FG') ], string='Goods Type',default="Materials",copy=True) line_ids_material = fields.One2many('sos_ir_line_material', 'ir_id', string="Materials Lines",copy=True) vehicle_type = fields.Selection([ ('yes', 'Yes'), ('no', 'No'), ],string="Material Received in Top Closed Vehicle") boxes_sealing = fields.Selection([ ('yes', 'Yes'), ('no', 'No'), ], string="Boxes/Bag/Barrels/Rolls Sealing shall be in-tact") line_ids_sfg = fields.One2many('sos_ir_line_sfg', 'ir_id', string="Components for SFG",copy=True) line_ids_fg = fields.One2many('sos_ir_line_fg', 'ir_id', string="Components for FG",copy=True) stores_approval_name = fields.Many2one('res.users', string='Stores Received By') stores_approval_image = fields.Image(related="stores_approval_name.signature_image",string='Stores-RM/PM In Charge') stores_approved_on = fields.Datetime(string="Approved On") indent_no = fields.Many2one('sos_fg_plan',string="Indent No") top_management_name = fields.Many2one('res.users', string='Top Management Approver') top_management_approval_image = fields.Image(related="top_management_name.signature_image",string='Top Management Approval') top_management_approved_on = fields.Datetime(string="Approved On") wo_planned_at = fields.Selection([('inhouse', 'In-House'),('outsource', 'Out-Sourcing')],default="outsource",string="W.O Planned at") dept_in_charge_name = fields.Many2one('res.users', string='Department In-Charge') dept_in_charge_image = fields.Image(related="dept_in_charge_name.signature_image",string='Department In-Charge Sign',readonly=True) dept_in_charge_approved_on = fields.Datetime(string="Approved On") test_report = fields.Binary(string="DC/Invoice Document") test_report_filename=fields.Char(string="DC DocumentFile Name") #Rework orr_no = fields.Many2one('sos_sfg_outsourcing_return_register',string="Ref No") iqi_no = fields.Many2one('sos_iqi',string="IQI No",related="orr_no.iqi_no") currency_id = fields.Many2one('res.currency', string='Currency') service_charge = fields.Monetary(string="Service Charge",currency_field='currency_id') _sql_constraints = [ ('ir_no_unique', 'UNIQUE(ir_no)', 'The IR No must be unique!') ] @api.onchange('orr_no') def _onchange_orr_no(self): if self.orr_no: ir_ref_no = self.orr_no.iqi_no.ir_id_unique_id matching_ir_records = self.env['sos_ir'].search([('ir_no', 'like', f"{ir_ref_no.ir_no}%")], limit=1) variable = matching_ir_records.ir_no if variable[-1].isdigit(): next_char = "(a)" self.ir_no = variable + next_char else: last_char = variable[-2] if 'a' <= last_char <= 'z': next_char = f"({chr(ord(last_char) + 1)})" if last_char != 'z' else "(a)" new_variable = variable[:-3] self.ir_no = new_variable + next_char self.received_goods_type = self.orr_no.goods_type if self.orr_no.goods_type == "SFG": self.service_provider_name = ir_ref_no.service_provider_name self.wo_no = ir_ref_no.wo_no sfg_lines = [(5, 0, 0)] sfg_lines.append((0, 0, { 'component_id': self.iqi_no.sfg_name, 'qty': self.iqi_no.rejected_qty, 'order_qty': self.iqi_no.rejected_qty })) self.line_ids_sfg = sfg_lines else: self.supplier_name = ir_ref_no.supplier_name #self.po_no = ir_ref_no.po_no material_lines = [(5, 0, 0)] material_lines.append((0, 0, { 'component_id': self.iqi_no.material_name, 'qty': self.iqi_no.rejected_qty, 'order_qty': self.iqi_no.rejected_qty })) self.line_ids_material = material_lines self.parcel_count = ir_ref_no.parcel_count self.vehicle_type = ir_ref_no.vehicle_type self.boxes_sealing = ir_ref_no.boxes_sealing self.test_report = ir_ref_no.test_report self.test_report_filename = ir_ref_no.test_report_filename def action_view_invoice(self): """Action to view the PDF of the test report.""" # Check if there is a test report if not self.test_report: raise UserError("No test report available for this record.") # Use `ir.actions.act_url` to open the binary file as a PDF return { 'type': 'ir.actions.act_url', 'url': '/web/content/{}/{}/{}?download=false'.format( self._name, self.id, 'test_report'), 'target': 'new', # This opens the PDF in a new tab } @api.onchange('po_no') def _onchange_po_no(self): if self.po_no: try: lines = [(5, 0, 0)] for param in self.po_no.line_ids: if param.status in [0, 1]: if param.prev_received_qty < param.quantity: qty = param.quantity - param.prev_received_qty else: qty = param.quantity lines.append((0, 0, { 'component_id': param.component_id.id, 'qty': qty, 'order_qty': param.quantity, 'unit_price': param.unit_price })) self.line_ids_material = lines except Exception as e: print("Error processing po_no: %s", str(e)) @api.onchange('wo_no') def _onchange_wo_no(self): if self.wo_no: try: lines = [(5, 0, 0)] for param in self.wo_no.line_ids: lines.append((0, 0, { 'component_id': param.component_id.id, 'qty': param.quantity, 'order_qty': param.quantity })) self.line_ids_sfg = lines except Exception as e: print("Error processing po_no: %s", str(e)) @api.onchange('wo_no_inhouse') def _onchange_wo_no_inhouse(self): if self.wo_no_inhouse: try: lines = [(5, 0, 0)] for param in self.wo_no_inhouse.line_ids: lines.append((0, 0, { 'component_id': param.component_id.id, 'qty': param.quantity, 'order_qty': param.quantity })) self.line_ids_sfg = lines except Exception as e: print("Error processing po_no: %s", str(e)) def action_report_ir_btn(self): try: action = self.env.ref("sos_inventory.action_report_ir").report_action(self) return action except ValueError as e: print(f"Failed to find report action: {e}") def _generate_id(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_ir','IR', 'ir_no') def action_report_esign_btn(self): iqi_model = self.env['sos_iqi'] grn_model = self.env['sos_grn'] grn_line_model = self.env['sos_grn_line'] sequence_util = self.env['sos_common_scripts'] material_model = self.env['sos_material'] iqi_no = sequence_util.generate_sequence('sos_iqi', 'iqi', 'iqi_no') grn_no = sequence_util.generate_sequence('sos_grn', 'GRN', 'grn_no') if self.received_goods_type == "Materials": iqi_record = None grn_record = None iqi_lines_to_create = [] grn_line_values = [] for item in self.line_ids_material: # Fetch the component related to the current item component = self.env['sos_material'].browse(item.component_id.id) if self.supplier_name and self.supplier_name.id not in component.suppliers.ids: component.write({ 'suppliers': [(4, self.supplier_name.id)] }) if component.shelf_life == "yes": shelflife_line_values = { 'ir_ref_no':self.id, 'name': item.component_id.id, # Reference the created GRN 'quantity': item.qty, 'expiry_date':item.expiry_date } shellife_record = self.env['sos_shelflife_register'].create(shelflife_line_values) #raise UserError("The PO Number already exists. Validation failed.") if self.po_no: for pos in self.po_no.line_ids: if component.id == pos.component_id.id: if item.qty >= pos.quantity: pos.status = 2 pos.prev_received_qty = item.qty self.po_no.received_qty += 1 elif item.qty > 0: pos.prev_received_qty = pos.prev_received_qty + item.qty pos.status = 1 if pos.prev_received_qty >= pos.quantity: pos.status = 2 self.po_no.received_qty += 1 else: pos.status = 0 if component.inspection_method == 10: if not grn_record: grn_record_values = { 'grn_no': grn_no, 'ir_no':self.id, 'supplier_name': self.supplier_name.id, 'received_goods_type': 'Materials', 'supplier_invoice_no':self.dc_no_char, 'po_no':self.po_no.id } if iqi_record: grn_record_values['iqi_no'] = iqi_record.id grn_record = grn_model.with_context(from_script=True).create(grn_record_values) if item.qty > 0: grn_line_values = { 'grn_id': grn_record.id, # Reference the created GRN 'component_id': item.component_id.id, 'received_qty': item.qty, 'approved_qty':item.qty, 'invoice_qty':item.order_qty, 'unit_price':item.unit_price } grn_line_model.with_context(from_script=True).create(grn_line_values) else: iqi_record = self.env['sos_iqi'].create({ 'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'), 'material_option':True, 'sfg_option':False, 'supplier_name': self.supplier_name.id, 'batch_no':item.batch_no, 'received_qty':item.qty, 'uom': item.component_id.uom, 'material_name': item.component_id.id, 'material_code': item.component_id.material_code, 'in_tact':self.boxes_sealing, 'invoice_no':self.dc_no_char, 'invoice_date':self.dc_date, 'ir_id_unique_id':self.id, 'from_origin':"Vendor", 'unit_price':item.unit_price }) # Email part body_html = f"""
Below IQI is waiting for your Approval
""" send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,'sos_iqi',iqi_record.id,"deenalaura.m@sosaley.in","IQI Approval Request",body_html,'sos_inventory.sos_qc_user') # Email part ends elif self.received_goods_type == "SFG": for item in self.line_ids_sfg: # PO update part sfg_component = self.env['sos_sfg'].browse(item.component_id.id) if self.service_provider_name and self.service_provider_name.id not in sfg_component.service_providers.ids: sfg_component.write({ 'service_providers': [(4, self.service_provider_name.id)] }) if self.wo_planned_at == "outsource": if self.wo_no: if not self.orr_no: for pos in self.wo_no.line_ids: if sfg_component.id == pos.component_id.id: pos.last_received_quantity += item.qty else: if self.wo_no_inhouse: if not self.orr_no: for pos in self.wo_no_inhouse.line_ids: if sfg_component.id == pos.component_id.id: pos.last_received_quantity = pos.last_received_quantity + item.qty iqi_data = { 'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'), 'material_option':False, 'sfg_option':True, 'service_provider_name': self.service_provider_name.id, 'batch_no':item.batch_no, 'received_qty':item.qty, 'sfg_name': item.component_id.id, 'sfg_code': item.component_id.sfg_code, 'in_tact':self.boxes_sealing, 'invoice_no':self.dc_no_char, 'invoice_date':self.dc_date, 'ir_id_unique_id':self.id, 'from_origin':"Vendor" } if self.iqi_no.id: iqi_data['iqi_no'] = sequence_util.generate_sequence('sos_iqi', 'R-IQI', 'iqi_no') iqi_data['old_iqi_ref'] = self.iqi_no.id iqi_data['iqi_type'] = 'rework' # Rework Iteration starts sos_record = self.env['sos_iqi'].search([('id', '=', self.iqi_no.id)], limit=1) if sos_record: rework_iteration = sos_record.reworked_count + 1 sos_record.write({ 'reworked_count':rework_iteration }) # Rework Iteration ends iqi_record = self.env['sos_iqi'].create(iqi_data) body_html = f"""Below IQI is waiting for your response
""" send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,"sos_iqi",iqi_record.id,"deenalaura.m@sosaley.in","IQI Request",body_html,'sos_inventory.sos_qc_user') sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( self, 'stores_approval_name', 'stores_approved_on', 'sos_inventory.sos_scg_group_user' ) # Email part body_html = f"""Below Inward is waiting for your Approval
""" send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,"sos_ir",self.id,"deenalaura.m@sosaley.in","Incoming Material Received",body_html,'sos_inventory.sos_scg_group_manager') # Email part ends def action_deptincharge_esign_btn(self): # Email part body_html = f"""Below Inward is waiting for your Approval
""" subject = f"Inward Approval Request - {self.ir_no}" send_email = self.env['sos_common_scripts'] send_email.send_direct_email(self.env,"sos_ir",self.id,"ramachandran.r@sosaley.in",subject,body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( self, 'dept_in_charge_name', 'dept_in_charge_approved_on' ) def action_topmanagement_esign_btn(self): sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( self, 'top_management_name', 'top_management_approved_on', 'sos_inventory.sos_management_user' ) body_html = f"""Below Inward was received
""" send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,"sos_ir",self.id,"deenalaura.m@sosaley.in","Material Received",body_html,'sos_inventory.sos_finance_user') class SOS_IR_Line_Material(models.Model): _name = 'sos_ir_line_material' _description = 'Inward Register Material Lines' ir_id = fields.Many2one('sos_ir', string="IR", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Part No", required=True) name = fields.Char(related="component_id.name") uom = fields.Selection(related="component_id.uom") inspection_method = fields.Integer(related="component_id.inspection_method") material_code = fields.Char(related="component_id.material_code") batch_no = fields.Char(string="Batch No / Lot No") order_qty = fields.Integer(string="Order Quantity") invoice_qty = fields.Integer(string="Invoice Quantity") qty = fields.Integer(string="Received Quantity") currency_id = fields.Many2one('res.currency', string='Currency') unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id') test_report = fields.Binary(string="Test Report") test_report_filename=fields.Char(string="Test Report File Name") expiry_date = fields.Date(string="Expiry Date") shelf_life = fields.Selection([('yes', 'Yes'), ('no', 'No')],related="component_id.shelf_life", string="Shelf Life") @api.onchange('component_id') def _onchange_component_id(self): if self.component_id: self.unit_price = self.component_id.unit_price def action_view_pdf(self): """Action to view the PDF of the test report.""" # Check if there is a test report if not self.test_report: raise UserError("No test report available for this record.") # Use `ir.actions.act_url` to open the binary file as a PDF return { 'type': 'ir.actions.act_url', 'url': '/web/content/{}/{}/{}?download=false'.format( self._name, self.id, 'test_report'), 'target': 'new', # This opens the PDF in a new tab } class SOS_IR_Line_SFG(models.Model): _name = 'sos_ir_line_sfg' _description = 'Inward Register SFG Lines' ir_id = fields.Many2one('sos_ir', string="IR", ondelete="cascade") component_id = fields.Many2one('sos_sfg', string="Part No", required=True) sfg_code = fields.Char(related="component_id.sfg_code") batch_no = fields.Char(string="Batch No / Lot No") invoice_qty = fields.Integer(string="Invoice Quantity") order_qty = fields.Integer(string="Order Quantity") qty = fields.Integer(string="Received Quantity") test_report = fields.Binary(string="Test Report") test_report_filename=fields.Char(string="Test Report File Name") def action_view_pdf(self): """Action to view the PDF of the test report.""" # Check if there is a test report if not self.test_report: raise UserError("No test report available for this record.") # Use `ir.actions.act_url` to open the binary file as a PDF return { 'type': 'ir.actions.act_url', 'url': '/web/content/{}/{}/{}?download=false'.format( self._name, self.id, 'test_report'), 'target': 'new', # This opens the PDF in a new tab } class SOS_IR_Line_FG(models.Model): _name = 'sos_ir_line_fg' _description = 'Inward Register FG Lines' ir_id = fields.Many2one('sos_ir', string="IR", ondelete="cascade") component_id = fields.Many2one('sos_fg', string="Part No", required=True) fg_code = fields.Char(related="component_id.fg_code") batch_no = fields.Char(string="Batch No / Lot No") invoice_qty = fields.Integer(string="Invoice Quantity") order_qty = fields.Integer(string="Order Quantity") qty = fields.Integer(string="Received Quantity") test_report = fields.Binary(string="Test Report") test_report_filename=fields.Char(string="Test Report File Name") def action_view_pdf(self): """Action to view the PDF of the test report.""" # Check if there is a test report if not self.test_report: raise UserError("No test report available for this record.") # Use `ir.actions.act_url` to open the binary file as a PDF return { 'type': 'ir.actions.act_url', 'url': '/web/content/{}/{}/{}?download=false'.format( self._name, self.id, 'test_report'), 'target': 'new', # This opens the PDF in a new tab }