389 lines
20 KiB
Python
Executable File
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") |