Slink/sos_inventory/models/sos_iqi.py

389 lines
20 KiB
Python
Executable File

# -*- coding: utf-8 -*-
from odoo import models, fields, api
import time
from odoo.exceptions import UserError
from odoo.exceptions import ValidationError
class sos_iqi(models.Model):
_name = 'sos_iqi'
_description = 'Incoming Quality Inspection'
_rec_name = 'iqi_no'
_order = 'id desc'
iqi_no = fields.Char(string="IQI No", readonly= True, required= True, default=lambda self: self._generate_id())
iqi_date = fields.Datetime(string="IQI Date", default=fields.Datetime.now)
ir_id_unique_id=fields.Many2one('sos_ir', string='Inward Ref No')
test_report = fields.Selection([('yes','YES'),('no','NO')],string='Test Report Received',help="If No, action taken (Collect Material inspection report")
in_tact = fields.Selection([('yes','YES'),('no','NO')],string='Boxes/Bag/Barrels/Rolls Sealing shall be in-tact',help="If No, Is opened Boxes / Bags / Barrels/Rolls are identified and stored separately, intimate to QC and Supplier/Service provider.")
inspection_label = fields.Selection([('yes','YES'),('no','NO'),('na','NA')],string="Identification Label affixed post inspection")
review_test_report = fields.Selection([('yes','YES'),('no','NO')],string="Reviewed the Material Test reports.Any changes in the material specification",help="If Yes, is it Adequate / Needs More Information / Updated Quality Plan")
test_report_no = fields.Char(string="Material Test Report No")
test_report_doc = fields.Binary(string="Test Report")
test_report_filename=fields.Char(string="Test Report Name")
batch_no = fields.Text(string="Batch No")
serial_no = fields.Text(string="Serial No")
fg_name = fields.Many2one('sos_fg', string='FG Name')
iqi_type = fields.Selection([('new','New'),('rework','Reworked')],string='IQI Type',default='new')
material_name = fields.Many2one('sos_material', string="Material Name")
material_code = fields.Char(string="Material Code")
supplier_name = fields.Many2one('sos_suppliers',string="Supplier Name")
material_category = fields.Many2one('sos_material_configuration',string="Material Category")
uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], string="UOM")
wo_planned_at = fields.Selection([('inhouse', 'In-House'),('outsource', 'Out-Sourcing')],default="outsource",string="W.O Planned at")
rca_required = fields.Selection([('yes', 'Yes'),('no', 'No')], string="RCA Required")
rca_notes_text=fields.Text(string="Notes",default="The requirement for a Root Cause Analysis (RCA) is determined by defect severity, recurrence, or a defect rate below 10,000 parts per million (PPM).")
sfg_name = fields.Many2one('sos_sfg', string="SFG Name")
sfg_code = fields.Char(string="SFG Code",related="sfg_name.sfg_code")
service_provider_name = fields.Many2one('sos_service_providers',string="Service Provider Name")
sfg_category = fields.Many2one('sos_sfg_configuration',string="SFG Category")
invoice_no = fields.Char(string="Invoice No")
invoice_date = fields.Datetime(string="Invoice date")
received_qty = fields.Integer(string="Received Quantity")
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')
testing_line_ids = fields.One2many('sos_testing_parameters_line', 'ref_id', ondelete='cascade')
calibration_line_ids = fields.One2many('sos_iqi_calibration_line','calibration_id', ondelete='cascade')
material_option = fields.Boolean('Materials', default=True)
sfg_option = fields.Boolean('Semi-Finished Goods')
prepared_by_name = fields.Many2one('res.users', string='Stores Provided by')
prepared_by_image = fields.Image(related="prepared_by_name.signature_image",string='Prepared by Sign',readonly=True)
prepared_on = fields.Date(string="Prepared On")
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",required=True)
qc_by_name = fields.Many2one('res.users', string='QC Tested by')
qc_by_image = fields.Image(related="qc_by_name.signature_image",string='QC Tested Sign',readonly=True)
qc_tested_on = fields.Date(string="QC Tested On")
stores_received_by = fields.Many2one('res.users', string='Stores Received by')
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")
qa_by_name = fields.Many2one('res.users', string='QA Approved By')
qa_by_image = fields.Image(related="qa_by_name.signature_image",string='QA Approved by Sign',readonly=True)
qa_tested_on = fields.Date(string="QA Approved On")
qa_comments = fields.Text(string="QA Comments")
ppm = fields.Integer(string="PPM",compute="_compute_ppm")
reworked_count = fields.Integer(string="Reworked Count",default=0)
old_iqi_ref = fields.Many2one('sos_iqi',string="Rework References")
status = fields.Selection([ ('open', 'Open'),('closed', 'Closed')], default='open' , string="Status")
batch_allotmnet = fields.Boolean(string="Allot Batch")
batch_allotmnet_field = fields.Char(string="Other Field", compute='_compute_batch_allotmnet', store=True)
ncmr_ref = fields.Many2one('sos_ncmr',string="NCMR Reference (If any Rejected)")
from_origin = fields.Selection([('Vendor','Vendor'),('In-House','In-House')],string="Received From",default="Vendor")
currency_id = fields.Many2one('res.currency', string='Currency')
unit_price = fields.Monetary(string="Unit Price", currency_field='currency_id')
@api.onchange('received_qty', 'approved_qty')
def _onchange_rejected_qty(self):
if self.received_qty and self.approved_qty:
self.rejected_qty = self.received_qty - self.approved_qty
@api.depends('batch_allotmnet')
def _compute_batch_allotmnet(self):
for record in self:
if record.batch_allotmnet:
new_record = self.env['sos_batch_allotment_register'].create({
'sfg_name': record.sfg_name.id,
'alloted_date':record.iqi_date,
'batch_size':record.received_qty,
'iqi_ref_no':record.id
})
@api.depends('received_qty', 'rejected_qty')
def _compute_ppm(self):
for record in self:
if record.rejected_qty != 0 and record.received_qty != 0:
record.ppm = (record.rejected_qty / record.received_qty) * 10**6
else:
record.ppm = 0
def action_report_iqi_btn(self):
try:
action = self.env.ref("sos_inventory.action_report_iqi").report_action(self)
return action
except ValueError as e:
print(f"Failed to find report action: {e}")
def action_view_report(self):
if not self.test_report_doc:
raise UserError("No test report available for this record.")
return {
'type': 'ir.actions.act_url',
'url': '/web/content/{}/{}/{}?download=false'.format(
self._name, self.id, 'test_report_doc'),
'target': 'new', # This opens the PDF in a new tab
}
@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('received_qty', 'rejected_qty')
def _compute_rejected_percentage(self):
for record in self:
if record.received_qty > 0:
record.rejection_percentage = (record.rejected_qty / record.received_qty) * 100
else:
record.rejection_percentage = 0
@api.onchange('material_category')
def _onchange_material_category(self):
if self.material_category:
self._load_testing_parameters('material')
@api.onchange('sfg_category')
def _onchange_sfg_category(self):
if self.sfg_category:
self._load_testing_parameters('sfg')
def _load_testing_parameters(self,types):
if types == 'material':
if self.material_category:
testing_parameters = self.env['sos_material_configuration'].search([('id', '=', self.material_category.id)])
if not testing_parameters:
raise UserError('No testing parameters found for this Item.')
lines = [(5, 0, 0)]
sorted_parameters = testing_parameters.parameter_ids.sorted(key=lambda param: param.sequence)
for param in sorted_parameters:
lines.append((0, 0, {
'testing_parameter': param.name,
'req_readings':param.observation,
'obtained_readings':param.obtained_observation
}))
self.testing_line_ids = lines
else:
if self.sfg_category:
testing_parameters = self.env['sos_sfg_configuration'].search([('id', '=', self.sfg_category.id)])
if not testing_parameters:
raise UserError('No testing parameters found for this Item.')
lines = [(5, 0, 0)]
sorted_parameters = testing_parameters.parameter_ids.sorted(key=lambda param: param.sequence)
for param in sorted_parameters:
lines.append((0, 0, {
'testing_parameter': param.name,
'req_readings':param.observation,
'obtained_readings':param.obtained_observation
}))
self.testing_line_ids = lines
@api.onchange('material_option')
def _onchange_material_option(self):
if self.material_option:
self.sfg_option = False
@api.onchange('sfg_option')
def _onchange_sfg_option(self):
if self.sfg_option:
self.material_option = False
def _generate_id(self):
sequence_util = self.env['sos_common_scripts']
return sequence_util.generate_sequence('sos_iqi','IQI', 'iqi_no')
def action_report_esign_btn(self):
# Email part
body_html = f"""
<p>Below <b>IQI</b> is waiting for your Approval</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,'sos_iqi',self.id,"deenalaura.m@sosaley.in","IQI Approval Request",body_html,'sos_inventory.sos_qc_user')
# Email part ends
sequence_util = self.env['sos_common_scripts']
return sequence_util.action_assign_signature(
self,
'prepared_by_name',
'prepared_on'
)
def action_qc_esign_btn(self):
if self.approved_qty == 0 and self.rejected_qty == 0:
raise UserError("Please enter Approved Quantity or Rejected Quantity before proceeding.")
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:
if self.material_option:
ncmr_record = self.env['sos_ncmr'].create({
'ncmr_no': ncmr_id,
'material_option':True,
'sfg_option':False,
'batch_no':self.batch_no,
'rejected_qty':self.rejected_qty,
'material_name': self.material_name.id,
'material_code': self.material_name.material_code,
'incoming_doc_ref':self.id,
'department':'Quality Control',
'rca_required':self.rca_required
})
else:
ncmr_record = self.env['sos_ncmr'].create({
'ncmr_no': ncmr_id,
'material_option':False,
'sfg_option':True,
'batch_no':self.batch_no,
'rejected_qty':self.rejected_qty,
'sfg_name': self.sfg_name.id,
'sfg_code': self.sfg_name.sfg_code,
'incoming_doc_ref':self.id,
'department':'Quality Control',
'rca_required':self.rca_required
})
# Email part
body_html = f"""
<p>Below <b>IQI</b> is waiting for your Approval</p>
"""
ncmr_body_html = f"""
<p>Below <b>NCMR</b> is waiting for your Inspection</p>
"""
if ncmr_record:
self.ncmr_ref = ncmr_record.id
sequence_util.send_group_email(self.env,'sos_ncmr',ncmr_record.id,"deenalaura.m@sosaley.in","NCMR Inspection Pending",ncmr_body_html,'sos_inventory.sos_qc_user')
sequence_util.send_group_email(self.env,'sos_iqi',self.id,"deenalaura.m@sosaley.in","IQI Approval Request",body_html,'sos_inventory.sos_scg_group_user')
# Email part ends
return sequence_util.action_assign_signature(
self,
'qc_by_name',
'qc_tested_on'
)
def action_qa_esign_btn(self):
self.status = "closed"
if self.ncmr_ref:
self.ncmr_ref.rca_required = self.rca_required
self.ncmr_ref.rca_notes_text = self.rca_notes_text
# Email part
body_html = f"""
<p>Below <b>IQI</b> is waiting for your Approval</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,'sos_iqi',self.id,"deenalaura.m@sosaley.in","IQI 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 generate_grn(self):
sequence_util = self.env['sos_common_scripts']
grn_no = sequence_util.generate_sequence('sos_grn', 'GRN', 'grn_no')
grn_record = None
grn_line_values = []
if self.material_option == True:
grn_record = self.env['sos_grn'].with_context(from_script=True).create({
'grn_no': grn_no,
'iqi_no': self.id,
'ir_no':self.ir_id_unique_id.id,
'supplier_name': self.supplier_name.id,
'received_goods_type': 'Materials',
'supplier_invoice_no':self.invoice_no,
'po_no':self.ir_id_unique_id.po_no.id
})
grn_line_values = self.env['sos_grn_line'].with_context(from_script=True).create({
'grn_id': grn_record.id,
'component_id': self.material_name.id,
'received_qty': self.received_qty,
'approved_qty':self.approved_qty,
'rejected_qty':self.rejected_qty,
'invoice_qty': self.received_qty,
'unit_price':self.unit_price
})
elif self.sfg_option == True:
if self.from_origin == "Vendor":
grn_record = self.env['sos_grn'].with_context(from_script=True).create({
'grn_no': grn_no,
'iqi_no': self.id,
'ir_no':self.ir_id_unique_id.id,
'service_provider_name': self.service_provider_name.id,
'received_goods_type': 'SFG',
'wo_no':self.ir_id_unique_id.wo_no.id,
'supplier_invoice_no':self.ir_id_unique_id.dc_no_char
})
grn_line_values = self.env['sos_grn_line_sfg'].with_context(from_script=True).create({
'grn_id': grn_record.id,
'component_id': self.sfg_name.id,
'received_qty': self.received_qty,
'approved_qty':self.approved_qty,
'rejected_qty':self.rejected_qty
})
else:
approved_qty = self.approved_qty
current_qty = self.sfg_name.inhand_stock_qty
current_value = self.sfg_name.unit_price
new_qty = current_qty + approved_qty
if new_qty > 0:
new_unit_price = ((current_qty * current_value) + (approved_qty * self.sfg_name.unit_price)) / new_qty
else:
new_unit_price = self.sfg_name.unit_price
self.sfg_name.inhand_stock_qty = new_qty
self.sfg_name.unit_price = new_unit_price
if approved_qty > 0:
self.env['sos_sfg_transaction_history'].create({
'ref_id': self.sfg_name.id,
'iqi_no': self.id,
'component_id': self.sfg_name.id,
'quantity': approved_qty,
'unit_price': self.sfg_name.unit_price,
'action': 'in',
})
def action_stores_received_esign_btn(self):
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'
)
self.generate_grn()
# Email part
body_html = f"""
<p>Below <b>IQI</b> is waiting for your Approval</p>
"""
send_email = self.env['sos_common_scripts']
send_email.send_group_email(self.env,'sos_iqi',self.id,"deenalaura.m@sosaley.in","IQI Approval Request",body_html,'sos_inventory.sos_qa_user')
# Email part ends
class sos_testing_lines(models.Model):
_name = 'sos_testing_parameters_line'
_description = 'Testing Parameters Lines'
ref_id = fields.Many2one('sos_iqi', string="Materials", ondelete="cascade")
qp_no = fields.Char(string="QP No")
testing_parameter = fields.Char(string="Testing Parameter")
req_readings = fields.Char(string="Required Readings / Observation")
obtained_readings = fields.Char(string="Obtained Readings / Observation")
inspection_remark = fields.Selection([('PASS','PASS'),('FAIL','FAIL')],string="Inspection Decision")
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")
aodr_qty = fields.Integer(string="Accepted on Deviation (or) Reworked Qty (If any)")
aodr_no = fields.Many2one('sos_aodr',string="AODR NO")
class SOS_iqi_calibration_line(models.Model):
_name = 'sos_iqi_calibration_line'
_description = 'Calibration Devices of IQI'
calibration_id = fields.Many2one('sos_iqi', string="Materials", ondelete="cascade")
name = fields.Many2one('sos_calibration_devices',string="Equipment Name", required=True)
s_no = fields.Char(string="Equipment Serial No",related="name.s_no")
identification_no= fields.Char(string="Identification No",related="name.identification_no")
certification_no= fields.Char(string="Certification No",related="name.certification_no")
calibrated_on = fields.Date(string="Calibrated On",related="name.calibrated_on")
calibrated_due = fields.Date(string="Calibration Due",related="name.calibrated_due")